Reduce GPS logger RAM usage on Uno

Keep lookup tables, sentence IDs, logger messages and commands in flash; remove the unused SPI buffer. Keep setup separate so SD initialization does not retain its stack frame during logging.

Co-authored-by: Limor Fried <ladyada@users.noreply.github.com>
This commit is contained in:
ladyadaandLimor Fried committed 2026-09-15 10:05:03 -04:00
1 parent 06f8376021
commit 957153e23c
5 files changed
+180 -108

No files matched your search

+17 -15
View File
@@ -74,6 +74,8 @@ void error(uint8_t errno) {
}
}
// Keep SD initialization buffers off the stack once logging starts.
void setup() __attribute__((noinline));
void setup() {
// for Leonardos, if you want to debug SD issues, uncomment this line
// to see serial output
@@ -82,7 +84,7 @@ void setup() {
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
// also spit it out
Serial.begin(115200);
Serial.println("\r\nUltimate GPSlogger Shield");
Serial.println(F("\r\nUltimate GPSlogger Shield"));
pinMode(ledPin, OUTPUT);
// make sure that the default chip select pin is set to
@@ -90,11 +92,11 @@ void setup() {
pinMode(10, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println("Card init. failed!");
Serial.println(F("Card init. failed!"));
error(2);
}
char filename[15];
strcpy(filename, "GPSLOG00.TXT");
char filename[12];
strcpy_P(filename, PSTR("GPSLOG00.TXT"));
for (uint8_t i = 0; i < 100; i++) {
filename[6] = '0' + i/10;
filename[7] = '0' + i%10;
@@ -106,27 +108,27 @@ void setup() {
logfile = SD.open(filename, FILE_WRITE);
if( ! logfile ) {
Serial.print("Couldnt create ");
Serial.print(F("Couldnt create "));
Serial.println(filename);
error(3);
}
Serial.print("Writing to ");
Serial.print(F("Writing to "));
Serial.println(filename);
// connect to the GPS at the desired rate
GPS.begin(9600);
// uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(F(PMTK_SET_NMEA_OUTPUT_RMCGGA));
// uncomment this line to turn on only the "minimum recommended" data
//GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
//GPS.sendCommand(F(PMTK_SET_NMEA_OUTPUT_RMCONLY));
// For logging data, we don't suggest using anything but either RMC only or RMC+GGA
// to keep the log files at a reasonable size
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 100 millihertz (once every 10 seconds), 1Hz or 5Hz update rate
GPS.sendCommand(F(PMTK_SET_NMEA_UPDATE_1HZ)); // 100 millihertz (once every 10 seconds), 1Hz or 5Hz update rate
// Turn off updates on antenna status, if the firmware permits it
GPS.sendCommand(PGCMD_NOANTENNA);
GPS.sendCommand(F(PGCMD_NOANTENNA));
// the nice thing about this code is you can have a timer0 interrupt go off
// every 1 millisecond, and read data from the GPS for you. that makes the
@@ -135,7 +137,7 @@ void setup() {
useInterrupt(true);
#endif
Serial.println("Ready!");
Serial.println(F("Ready!"));
}
@@ -192,19 +194,19 @@ void loop() {
return; // we can fail to parse a sentence in which case we should just wait for another
// Sentence parsed!
Serial.println("OK");
Serial.println(F("OK"));
if (LOG_FIXONLY && !GPS.fix) {
Serial.print("No Fix");
Serial.print(F("No Fix"));
return;
}
// Rad. lets log it!
Serial.println("Log");
Serial.println(F("Log"));
uint8_t stringsize = strlen(stringptr);
if (stringsize != logfile.write((uint8_t *)stringptr, stringsize)) //write the string to the SD file
error(4);
if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA")) logfile.flush();
if (strstr_P(stringptr, PSTR("RMC")) || strstr_P(stringptr, PSTR("GGA"))) logfile.flush();
Serial.println();
}
}
+8
View File
@@ -392,6 +392,14 @@ char Adafruit_GPS::read(void) {
/**************************************************************************/
void Adafruit_GPS::sendCommand(const char *str) { println(str); }
/**************************************************************************/
/*!
@brief Send a command stored in flash
@param str Command wrapped in F()
*/
/**************************************************************************/
void Adafruit_GPS::sendCommand(const __FlashStringHelper *str) { println(str); }
/**************************************************************************/
/*!
@brief Check to see if a new NMEA line has been received
+6 -20
View File
@@ -101,6 +101,7 @@ public:
size_t write(uint8_t);
char read(void);
void sendCommand(const char *);
void sendCommand(const __FlashStringHelper *);
bool newNMEAreceived();
void pause(bool b);
char *lastNMEA(void);
@@ -243,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);
@@ -253,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 sources[][4] PROGMEM; ///< valid source ids
static const char sentences_parsed[][4] PROGMEM; ///< parseable sentence ids
static const char sentences_known[][4] PROGMEM; ///< 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.
@@ -296,8 +284,6 @@ private:
int8_t gpsSPI_cs = -1;
SPISettings gpsSPI_settings =
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;
char _i2cbuffer[GPS_MAX_I2C_TRANSFER];
int8_t _buff_max = -1, _buff_idx = 0;
+62 -31
View File
@@ -84,7 +84,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// pruning excess code easier. Otherwise, keep them alphabetical for ease of
// reading.
if (!strcmp(thisSentence, "GGA")) { //************************************GGA
if (!strcmp_P(thisSentence,
PSTR("GGA"))) { //************************************GGA
// GGA Global Positioning System Fix Data. Time, Position and fix related
// data for a GPS receiver
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@@ -113,7 +114,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
(double)latitude, lat, (double)longitude, lon, fixquality,
satellites, (double)HDOP, (double)altitude, (double)geoidheight);
} else if (!strcmp(thisSentence, "GLL")) { //*****************************GLL
} else if (!strcmp_P(thisSentence,
PSTR("GLL"))) { //*****************************GLL
// GLL Geographic Position – Latitude/Longitude
// 1 2 3 4 5 6 7
// | | | | | | |
@@ -130,7 +132,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
(double)hour * 10000L + minute * 100L + seconds +
milliseconds / 1000.);
} else if (!strcmp(thisSentence, "GSA")) { //*****************************GSA
} else if (!strcmp_P(thisSentence,
PSTR("GSA"))) { //*****************************GSA
// GSA GPS DOP and active satellites
// 1 2 3 14 15 16 17 18
// | | | | | | | |
@@ -147,7 +150,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 18) Checksum
return NULL;
} else if (!strcmp(thisSentence, "RMC")) { //*****************************RMC
} else if (!strcmp_P(thisSentence,
PSTR("RMC"))) { //*****************************RMC
// RMC Recommended Minimum Navigation Information
// 12
// 1 2 3 4 5 6 7 8 9 10 11 |
@@ -172,7 +176,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
(double)angle, day * 10000 + month * 100 + year,
(double)magvariation, mag);
} else if (!strcmp(thisSentence, "APB")) { //*****************************APB
} else if (!strcmp_P(thisSentence,
PSTR("APB"))) { //*****************************APB
// APB Autopilot Sentence "B"
// 13 15
// 1 2 3 4 5 6 7 8 9 10 11 12 | 14 |
@@ -202,7 +207,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 15) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBK")) { //*****************************DBT
} else if (!strcmp_P(thisSentence,
PSTR("DBK"))) { //*****************************DBT
// DBK Depth Below Keel
// 1 2 3 4 5 6 7
// | | | | | | |
@@ -216,7 +222,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBS")) { //*****************************DBT
} else if (!strcmp_P(thisSentence,
PSTR("DBS"))) { //*****************************DBT
// DBS Depth Below Surface
// 1 2 3 4 5 6 7
// | | | | | | |
@@ -230,7 +237,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBT")) { //*****************************DBT
} else if (!strcmp_P(thisSentence,
PSTR("DBT"))) { //*****************************DBT
// DBT Depth Below Transducer
// 1 2 3 4 5 6 7
// | | | | | | |
@@ -245,7 +253,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
double d = val[NMEA_DEPTH].latest - depthToTransducer;
sprintf(p, "%f,f,%f,M,,,", d / 0.3048, d);
} else if (!strcmp(thisSentence, "DPT")) { //*****************************DPT
} else if (!strcmp_P(thisSentence,
PSTR("DPT"))) { //*****************************DPT
// DPT Heading – Deviation & Variation
// 1 2 3
// | | |
@@ -257,7 +266,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "GSV")) { //*****************************GSV
} else if (!strcmp_P(thisSentence,
PSTR("GSV"))) { //*****************************GSV
// GSV Satellites in view
// 1 2 3 4 5 6 7 n
// | | | | | | | |
@@ -273,7 +283,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// n) Checksum
return NULL;
} else if (!strcmp(thisSentence, "HDG")) { //*****************************HDG
} else if (!strcmp_P(thisSentence,
PSTR("HDG"))) { //*****************************HDG
// HDG Heading – Deviation & Variation
// 1 2 3 4 5 6
// | | | | | |
@@ -286,7 +297,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "HDM")) { //*****************************HDM
} else if (!strcmp_P(thisSentence,
PSTR("HDM"))) { //*****************************HDM
// HDM Heading – Magnetic
// 1 2 3
// | | |
@@ -296,7 +308,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 3) Checksum
sprintf(p, "%f,M", (double)val[NMEA_HDG].latest);
} else if (!strcmp(thisSentence, "HDT")) { //*****************************HDT
} else if (!strcmp_P(thisSentence,
PSTR("HDT"))) { //*****************************HDT
// HDT Heading – True
// 1 2 3
// | | |
@@ -307,7 +320,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// starts with $II for integrated instrumentation
sprintf(p, "%f,T", (double)val[NMEA_HDT].latest);
} else if (!strcmp(thisSentence, "MDA")) { //*****************************MDA
} else if (!strcmp_P(thisSentence,
PSTR("MDA"))) { //*****************************MDA
// MDA Meteorological Composite
// 1 2 3 4 5 6 7 8 9 10 11 12
// | | | | | | | | | | | |
@@ -328,7 +342,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 12) C or F
return NULL;
} else if (!strcmp(thisSentence, "MTW")) { //*****************************MTW
} else if (!strcmp_P(thisSentence,
PSTR("MTW"))) { //*****************************MTW
// MTW Water Temperature
// 1 2 3
// | | |
@@ -339,12 +354,14 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "MWD")) { //*****************************MWD
} else if (!strcmp_P(thisSentence,
PSTR("MWD"))) { //*****************************MWD
// MWD Wind Direction & Speed
// Format unknown
return NULL;
} else if (!strcmp(thisSentence, "MWV")) { //*****************************MWV
} else if (!strcmp_P(thisSentence,
PSTR("MWV"))) { //*****************************MWV
// MWV Wind Speed and Angle assuming values for True
// 1 2 3 4 5 6
// | | | | | |
@@ -363,7 +380,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
sprintf(p, "%f,%c,%f,N,A", (double)val[NMEA_TWA].latest, 'T',
(double)val[NMEA_TWS].latest);
} else if (!strcmp(thisSentence, "RMB")) { //*****************************RMB
} else if (!strcmp_P(thisSentence,
PSTR("RMB"))) { //*****************************RMB
// RMB Recommended Minimum Navigation Information
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14
// | | | | | | | | | | | | | |
@@ -381,7 +399,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 13) Arrival Status, A = Arrival Circle Entered 14) Checksum
sprintf(p, ",,,,,,,,,,,%f,A", (double)val[NMEA_VMGWP].latest);
} else if (!strcmp(thisSentence, "ROT")) { //*****************************ROT
} else if (!strcmp_P(thisSentence,
PSTR("ROT"))) { //*****************************ROT
// ROT Rate Of Turn
// 1 2 3
// | | |
@@ -391,7 +410,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "RPM")) { //*****************************RPM
} else if (!strcmp_P(thisSentence,
PSTR("RPM"))) { //*****************************RPM
// RPM Revolutions
// 1 2 3 4 5 6
// | | | | | |
@@ -404,7 +424,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "RSA")) { //*****************************RSA
} else if (!strcmp_P(thisSentence,
PSTR("RSA"))) { //*****************************RSA
// RSA Rudder Sensor Angle
// 1 2 3 4 5
// | | | | |
@@ -416,7 +437,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 5) Checksum
return NULL;
} else if (!strcmp(thisSentence, "TXT")) { //*****************************TXT
} else if (!strcmp_P(thisSentence,
PSTR("TXT"))) { //*****************************TXT
// as mentioned in https://github.com/adafruit/Adafruit_GPS/issues/95
// TXT Text Transmission
// 1 2 3 4 5
@@ -429,7 +451,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 5) Checksum
sprintf(p, "01,01,23,This is the text of the sample message");
} else if (!strcmp(thisSentence, "VDR")) { //*****************************VDR
} else if (!strcmp_P(thisSentence,
PSTR("VDR"))) { //*****************************VDR
// VDR Set and Drift
// 1 2 3 4 5 6 7
// | | | | | | |
@@ -443,7 +466,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VHW")) { //*****************************VHW
} else if (!strcmp_P(thisSentence,
PSTR("VHW"))) { //*****************************VHW
// VHW Water Speed and Heading
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
@@ -462,7 +486,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
(double)val[NMEA_HDG].latest, (double)val[NMEA_VTW].latest,
(double)val[NMEA_VTW].latest * 1.829);
} else if (!strcmp(thisSentence, "VLW")) { //*****************************VLW
} else if (!strcmp_P(thisSentence,
PSTR("VLW"))) { //*****************************VLW
// VLW Distance Traveled through Water
// 1 2 3 4 5
// | | | | |
@@ -476,7 +501,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 5) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VPW")) { //*****************************VPW
} else if (!strcmp_P(thisSentence,
PSTR("VPW"))) { //*****************************VPW
// not supported by iNavX
// VPW Speed – Measured Parallel to Wind
// 1 2 3 4 5
@@ -489,7 +515,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 5) Checksum
sprintf(p, "%f,N,,", (double)val[NMEA_VMG].latest);
} else if (!strcmp(thisSentence, "VTG")) { //*****************************VTG
} else if (!strcmp_P(thisSentence,
PSTR("VTG"))) { //*****************************VTG
// VTG Track Made Good and Ground Speed
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
@@ -501,7 +528,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 9) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VWR")) { //*****************************VWR
} else if (!strcmp_P(thisSentence,
PSTR("VWR"))) { //*****************************VWR
// VWR Relative Wind Speed and Angle
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
@@ -519,7 +547,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 9) Checksum
return NULL;
} else if (!strcmp(thisSentence, "WCV")) { //*****************************WCV
} else if (!strcmp_P(thisSentence,
PSTR("WCV"))) { //*****************************WCV
// WCV Waypoint Closure Velocity
// 1 2 3 4
// | | | |
@@ -527,7 +556,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 1) Velocity 2) N = knots 3) Waypoint ID 4) Checksum
sprintf(p, "%f,N,home", (double)val[NMEA_VMG].latest);
} else if (!strcmp(thisSentence, "XTE")) { //*****************************XTE
} else if (!strcmp_P(thisSentence,
PSTR("XTE"))) { //*****************************XTE
// XTE Cross-Track Error – Measured
// 1 2 3 4 5 6
// | | | | | |
@@ -545,7 +575,8 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "ZDA")) { //*****************************ZDA
} else if (!strcmp_P(thisSentence,
PSTR("ZDA"))) { //*****************************ZDA
// ZDA Time & Date – UTC, Day, Month, Year and Local Time Zone
// 1 2 3 4 5 6 7
// | | | | | | |
+87 -42
View File
@@ -21,6 +21,22 @@
/**************************************************************************/
#include <Adafruit_GPS.h>
const char Adafruit_GPS::sources[][4] PROGMEM = {"II", "WI", "GP", "PG", "GL",
"GA", "GN", "P", "ZZZ"};
#ifdef NMEA_EXTENSIONS
const char Adafruit_GPS::sentences_parsed[][4] PROGMEM = {
"GGA", "GLL", "GSA", "RMC", "DBT", "HDM", "HDT", "MDA", "MTW", "MWV",
"RMB", "TOP", "TXT", "VHW", "VLW", "VPW", "VWR", "WCV", "XTE", "ZZZ"};
const char Adafruit_GPS::sentences_known[][4] PROGMEM = {
"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 Adafruit_GPS::sentences_parsed[][4] PROGMEM = {"GGA", "GLL", "GSA",
"RMC", "TOP", "ZZZ"};
const char Adafruit_GPS::sentences_known[][4] PROGMEM = {"DBT", "HDM", "HDT",
"ZZZ"};
#endif
#include <ctype.h>
/**************************************************************************/
@@ -73,7 +89,8 @@ bool Adafruit_GPS::parse(char *nmea) {
// 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
if (!strcmp_P(thisSentence,
PSTR("GGA"))) { //************************************GGA
if (fields < 11)
return false;
// Adafruit from Actisense NGW-1 from SH CP150C
@@ -113,7 +130,8 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
geoidheight = atof(p); // skip the rest
} else if (!strcmp(thisSentence, "RMC")) { //*****************************RMC
} else if (!strcmp_P(thisSentence,
PSTR("RMC"))) { //*****************************RMC
if (fields < 9)
return false;
// in Adafruit from Actisense NGW-1 from SH CP150C
@@ -145,7 +163,8 @@ bool Adafruit_GPS::parse(char *nmea) {
lastDate = sentTime;
} // skip the rest
} else if (!strcmp(thisSentence, "GLL")) { //*****************************GLL
} else if (!strcmp_P(thisSentence,
PSTR("GLL"))) { //*****************************GLL
if (fields < 6)
return false;
// in Adafruit from Actisense NGW-1 from SH CP150C
@@ -163,7 +182,8 @@ bool Adafruit_GPS::parse(char *nmea) {
p = strchr(p, ',') + 1;
parseFix(p); // skip the rest
} else if (!strcmp(thisSentence, "GSA")) { //*****************************GSA
} else if (!strcmp_P(thisSentence,
PSTR("GSA"))) { //*****************************GSA
if (fields < 17)
return false;
// in Adafruit from Actisense NGW-1
@@ -185,7 +205,8 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
VDOP = atof(p); // last before checksum
} else if (!strcmp(thisSentence, "TOP")) { //*****************************TOP
} else if (!strcmp_P(thisSentence,
PSTR("TOP"))) { //*****************************TOP
if (fields < 2)
return false;
// See:
@@ -198,11 +219,13 @@ bool Adafruit_GPS::parse(char *nmea) {
}
#ifdef NMEA_EXTENSIONS // Sentences not required for basic GPS functionality
else if (!strcmp(thisSentence, "APB")) { //*******************************APB
else if (!strcmp_P(thisSentence,
PSTR("APB"))) { //*******************************APB
// from Actisense NGW-1 from SH CP150C
return false;
} else if (!strcmp(thisSentence, "DBT")) { //*****************************DBT
} else if (!strcmp_P(thisSentence,
PSTR("DBT"))) { //*****************************DBT
if (fields < 5)
return false;
// from Actisense NGW-1
@@ -221,27 +244,33 @@ bool Adafruit_GPS::parse(char *nmea) {
newDataValue(NMEA_DEPTH,
(nmea_float_t)atof(p) * 6 * 0.3048f + depthToTransducer);
} else if (!strcmp(thisSentence, "DPT")) { //*****************************DPT
} else if (!strcmp_P(thisSentence,
PSTR("DPT"))) { //*****************************DPT
// from Actisense NGW-1
return false;
} else if (!strcmp(thisSentence, "GSV")) { //*****************************GSV
} else if (!strcmp_P(thisSentence,
PSTR("GSV"))) { //*****************************GSV
// from Actisense NGW-1
return false;
} else if (!strcmp(thisSentence, "HDG")) { //*****************************HDG
} else if (!strcmp_P(thisSentence,
PSTR("HDG"))) { //*****************************HDG
// from Actisense NGW-1 from SH CP150C
return false;
} else if (!strcmp(thisSentence, "HDM")) { //*****************************HDM
} else if (!strcmp_P(thisSentence,
PSTR("HDM"))) { //*****************************HDM
if (!isEmpty(p))
newDataValue(NMEA_HDG, atof(p)); // skip the rest
} else if (!strcmp(thisSentence, "HDT")) { //*****************************HDT
} else if (!strcmp_P(thisSentence,
PSTR("HDT"))) { //*****************************HDT
if (!isEmpty(p))
newDataValue(NMEA_HDT, atof(p)); // skip the rest
} else if (!strcmp(thisSentence, "MDA")) { //*****************************MDA
} else if (!strcmp_P(thisSentence,
PSTR("MDA"))) { //*****************************MDA
if (fields < 9)
return false;
// from Actisense NGW-1
@@ -284,7 +313,8 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
newDataValue(NMEA_HUMIDITY, atof(p)); // skip the rest
} else if (!strcmp(thisSentence, "MTW")) { //*****************************MTW
} else if (!strcmp_P(thisSentence,
PSTR("MTW"))) { //*****************************MTW
if (fields < 2)
return false;
nmea_float_t T = 100000.;
@@ -301,11 +331,13 @@ bool Adafruit_GPS::parse(char *nmea) {
if (T < 1000)
newDataValue(NMEA_TEMPERATURE_WATER, T);
} else if (!strcmp(thisSentence, "MWD")) { //*****************************MWD
} else if (!strcmp_P(thisSentence,
PSTR("MWD"))) { //*****************************MWD
// from Actisense NGW-1
return false;
} else if (!strcmp(thisSentence, "MWV")) { //*****************************MWV
} else if (!strcmp_P(thisSentence,
PSTR("MWV"))) { //*****************************MWV
if (fields < 5)
return false;
// from Actisense NGW-1
@@ -350,7 +382,8 @@ bool Adafruit_GPS::parse(char *nmea) {
newDataValue(NMEA_TWS, spd);
}
} else if (!strcmp(thisSentence, "RMB")) { //*****************************RMB
} else if (!strcmp_P(thisSentence,
PSTR("RMB"))) { //*****************************RMB
if (fields < 12)
return false;
// from Actisense NGW-1 from SH CP150C
@@ -435,17 +468,21 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
newDataValue(NMEA_VMGWP, atof(p)); // skip arrival flag
} else if (!strcmp(thisSentence, "ROT")) { //*****************************ROT
} else if (!strcmp_P(thisSentence,
PSTR("ROT"))) { //*****************************ROT
return false;
} else if (!strcmp(thisSentence, "RPM")) { //*****************************RPM
} else if (!strcmp_P(thisSentence,
PSTR("RPM"))) { //*****************************RPM
return false;
} else if (!strcmp(thisSentence, "RSA")) { //*****************************RSA
} else if (!strcmp_P(thisSentence,
PSTR("RSA"))) { //*****************************RSA
// from Actisense NGW-1
return false;
} else if (!strcmp(thisSentence, "TXT")) { //*****************************TXT
} else if (!strcmp_P(thisSentence,
PSTR("TXT"))) { //*****************************TXT
if (fields < 4)
return false;
if (!isEmpty(p))
@@ -460,11 +497,13 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
parseStr(txtTXT, p, 61); // copy the text to NMEA TXT max of 61 characters
} else if (!strcmp(thisSentence, "VDR")) { //*****************************VDR
} else if (!strcmp_P(thisSentence,
PSTR("VDR"))) { //*****************************VDR
// from Actisense NGW-1
return false;
} else if (!strcmp(thisSentence, "VHW")) { //*****************************VHW
} else if (!strcmp_P(thisSentence,
PSTR("VHW"))) { //*****************************VHW
if (fields < 5)
return false;
// from Actisense NGW-1
@@ -479,7 +518,8 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
newDataValue(NMEA_VTW, atof(p)); // skip the other units
} else if (!strcmp(thisSentence, "VLW")) { //*****************************VLW
} else if (!strcmp_P(thisSentence,
PSTR("VLW"))) { //*****************************VLW
if (fields < 3)
return false;
// from Actisense NGW-1
@@ -490,7 +530,8 @@ bool Adafruit_GPS::parse(char *nmea) {
if (!isEmpty(p))
newDataValue(NMEA_LOGR, atof(p)); // skip the other units
} else if (!strcmp(thisSentence, "VPW")) { //*****************************VPW
} else if (!strcmp_P(thisSentence,
PSTR("VPW"))) { //*****************************VPW
if (fields < 3)
return false;
// knots, metres/s coerced to knots
@@ -503,11 +544,13 @@ bool Adafruit_GPS::parse(char *nmea) {
vmg = atof(p) * 0.3048 * 3600. / 6000.; // skip units
if (vmg < 1000.0f)
newDataValue(NMEA_VMG, vmg);
} else if (!strcmp(thisSentence, "VTG")) { //*****************************VTG
} else if (!strcmp_P(thisSentence,
PSTR("VTG"))) { //*****************************VTG
// from Actisense NGW-1 from SH CP150C
return false;
} else if (!strcmp(thisSentence, "VWR")) { //*****************************VWR
} else if (!strcmp_P(thisSentence,
PSTR("VWR"))) { //*****************************VWR
if (fields < 8)
return false;
// from Actisense NGW-1
@@ -557,12 +600,14 @@ bool Adafruit_GPS::parse(char *nmea) {
if (units == 'N')
newDataValue(NMEA_AWS, ws); // store the final result
} else if (!strcmp(thisSentence, "WCV")) { //*****************************WCV
} else if (!strcmp_P(thisSentence,
PSTR("WCV"))) { //*****************************WCV
// from SH CP150C
if (!isEmpty(p))
newDataValue(NMEA_VMGWP, atof(p)); // skip the rest
} else if (!strcmp(thisSentence, "XTE")) { //*****************************XTE
} else if (!strcmp_P(thisSentence,
PSTR("XTE"))) { //*****************************XTE
if (fields < 5)
return false;
// from Actisense NGW-1 from SH CP150C
@@ -582,7 +627,8 @@ bool Adafruit_GPS::parse(char *nmea) {
newDataValue(NMEA_XTE, xte);
} // skip units
} else if (!strcmp(thisSentence, "ZDA")) { //*****************************ZDA
} else if (!strcmp_P(thisSentence,
PSTR("ZDA"))) { //*****************************ZDA
// from Actisense NGW-1
return false;
}
@@ -648,20 +694,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 +722,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
}