mirror of
https://github.com/adafruit/Adafruit_GPS.git
synced 2026-10-27 06:20:18 +00:00
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:
1 parent
06f8376021
commit
957153e23c
5 files changed
+180
-108
No files matched your search
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user