restructure for msCode

This commit is contained in:
2021-01-25 10:02:31 +01:00
parent 957909193c
commit e3336a113f
256 changed files with 20639 additions and 8270 deletions

View File

@@ -0,0 +1 @@
{"type": "library", "name": "TinyGPSPlus", "version": "1.0.2", "spec": {"owner": "mikalhart", "id": 1655, "name": "TinyGPSPlus", "requirements": null, "url": null}}

View File

@@ -0,0 +1,91 @@
#include <TinyGPS++.h>
/*
This sample sketch should be the first you try out when you are testing a TinyGPS++
(TinyGPSPlus) installation. In normal use, you feed TinyGPS++ objects characters from
a serial NMEA GPS device, but this example uses static strings for simplicity.
*/
// A sample NMEA stream.
const char *gpsStream =
"$GPRMC,045103.000,A,3014.1984,N,09749.2872,W,0.67,161.46,030913,,,A*7C\r\n"
"$GPGGA,045104.000,3014.1985,N,09749.2873,W,1,09,1.2,211.6,M,-22.5,M,,0000*62\r\n"
"$GPRMC,045200.000,A,3014.3820,N,09748.9514,W,36.88,65.02,030913,,,A*77\r\n"
"$GPGGA,045201.000,3014.3864,N,09748.9411,W,1,10,1.2,200.8,M,-22.5,M,,0000*6C\r\n"
"$GPRMC,045251.000,A,3014.4275,N,09749.0626,W,0.51,217.94,030913,,,A*7D\r\n"
"$GPGGA,045252.000,3014.4273,N,09749.0628,W,1,09,1.3,206.9,M,-22.5,M,,0000*6F\r\n";
// The TinyGPS++ object
TinyGPSPlus gps;
void setup()
{
Serial.begin(115200);
Serial.println(F("BasicExample.ino"));
Serial.println(F("Basic demonstration of TinyGPS++ (no device needed)"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
while (*gpsStream)
if (gps.encode(*gpsStream++))
displayInfo();
Serial.println();
Serial.println(F("Done."));
}
void loop()
{
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
Serial.print(F("."));
if (gps.time.centisecond() < 10) Serial.print(F("0"));
Serial.print(gps.time.centisecond());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}

View File

@@ -0,0 +1,92 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("DeviceExample.ino"));
Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
Serial.print(F("."));
if (gps.time.centisecond() < 10) Serial.print(F("0"));
Serial.print(gps.time.centisecond());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}

View File

@@ -0,0 +1,159 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("FullExample.ino"));
Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
Serial.println(F("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum"));
Serial.println(F(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail"));
Serial.println(F("----------------------------------------------------------------------------------------------------------------------------------------"));
}
void loop()
{
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
printFloat(gps.hdop.hdop(), gps.hdop.isValid(), 6, 1);
printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
printInt(gps.location.age(), gps.location.isValid(), 5);
printDateTime(gps.date, gps.time);
printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.deg()) : "*** ", 6);
unsigned long distanceKmToLondon =
(unsigned long)TinyGPSPlus::distanceBetween(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON) / 1000;
printInt(distanceKmToLondon, gps.location.isValid(), 9);
double courseToLondon =
TinyGPSPlus::courseTo(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);
printFloat(courseToLondon, gps.location.isValid(), 7, 2);
const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);
printInt(gps.charsProcessed(), true, 6);
printInt(gps.sentencesWithFix(), true, 10);
printInt(gps.failedChecksum(), true, 9);
Serial.println();
smartDelay(1000);
if (millis() > 5000 && gps.charsProcessed() < 10)
Serial.println(F("No GPS data received: check wiring"));
}
// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
static void printFloat(float val, bool valid, int len, int prec)
{
if (!valid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartDelay(0);
}
static void printInt(unsigned long val, bool valid, int len)
{
char sz[32] = "*****************";
if (valid)
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
smartDelay(0);
}
static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
if (!d.isValid())
{
Serial.print(F("********** "));
}
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
Serial.print(sz);
}
if (!t.isValid())
{
Serial.print(F("******** "));
}
else
{
char sz[32];
sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
Serial.print(sz);
}
printInt(d.age(), d.isValid(), 5);
smartDelay(0);
}
static void printStr(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
smartDelay(0);
}

View File

@@ -0,0 +1,191 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample code demonstrates just about every built-in operation of TinyGPS++ (TinyGPSPlus).
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
// For stats that happen every 5 seconds
unsigned long last = 0UL;
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("KitchenSink.ino"));
Serial.println(F("Demonstrating nearly every feature of TinyGPS++"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
}
void loop()
{
// Dispatch incoming characters
while (ss.available() > 0)
gps.encode(ss.read());
if (gps.location.isUpdated())
{
Serial.print(F("LOCATION Fix Age="));
Serial.print(gps.location.age());
Serial.print(F("ms Raw Lat="));
Serial.print(gps.location.rawLat().negative ? "-" : "+");
Serial.print(gps.location.rawLat().deg);
Serial.print("[+");
Serial.print(gps.location.rawLat().billionths);
Serial.print(F(" billionths], Raw Long="));
Serial.print(gps.location.rawLng().negative ? "-" : "+");
Serial.print(gps.location.rawLng().deg);
Serial.print("[+");
Serial.print(gps.location.rawLng().billionths);
Serial.print(F(" billionths], Lat="));
Serial.print(gps.location.lat(), 6);
Serial.print(F(" Long="));
Serial.println(gps.location.lng(), 6);
}
else if (gps.date.isUpdated())
{
Serial.print(F("DATE Fix Age="));
Serial.print(gps.date.age());
Serial.print(F("ms Raw="));
Serial.print(gps.date.value());
Serial.print(F(" Year="));
Serial.print(gps.date.year());
Serial.print(F(" Month="));
Serial.print(gps.date.month());
Serial.print(F(" Day="));
Serial.println(gps.date.day());
}
else if (gps.time.isUpdated())
{
Serial.print(F("TIME Fix Age="));
Serial.print(gps.time.age());
Serial.print(F("ms Raw="));
Serial.print(gps.time.value());
Serial.print(F(" Hour="));
Serial.print(gps.time.hour());
Serial.print(F(" Minute="));
Serial.print(gps.time.minute());
Serial.print(F(" Second="));
Serial.print(gps.time.second());
Serial.print(F(" Hundredths="));
Serial.println(gps.time.centisecond());
}
else if (gps.speed.isUpdated())
{
Serial.print(F("SPEED Fix Age="));
Serial.print(gps.speed.age());
Serial.print(F("ms Raw="));
Serial.print(gps.speed.value());
Serial.print(F(" Knots="));
Serial.print(gps.speed.knots());
Serial.print(F(" MPH="));
Serial.print(gps.speed.mph());
Serial.print(F(" m/s="));
Serial.print(gps.speed.mps());
Serial.print(F(" km/h="));
Serial.println(gps.speed.kmph());
}
else if (gps.course.isUpdated())
{
Serial.print(F("COURSE Fix Age="));
Serial.print(gps.course.age());
Serial.print(F("ms Raw="));
Serial.print(gps.course.value());
Serial.print(F(" Deg="));
Serial.println(gps.course.deg());
}
else if (gps.altitude.isUpdated())
{
Serial.print(F("ALTITUDE Fix Age="));
Serial.print(gps.altitude.age());
Serial.print(F("ms Raw="));
Serial.print(gps.altitude.value());
Serial.print(F(" Meters="));
Serial.print(gps.altitude.meters());
Serial.print(F(" Miles="));
Serial.print(gps.altitude.miles());
Serial.print(F(" KM="));
Serial.print(gps.altitude.kilometers());
Serial.print(F(" Feet="));
Serial.println(gps.altitude.feet());
}
else if (gps.satellites.isUpdated())
{
Serial.print(F("SATELLITES Fix Age="));
Serial.print(gps.satellites.age());
Serial.print(F("ms Value="));
Serial.println(gps.satellites.value());
}
else if (gps.hdop.isUpdated())
{
Serial.print(F("HDOP Fix Age="));
Serial.print(gps.hdop.age());
Serial.print(F("ms raw="));
Serial.print(gps.hdop.value());
Serial.print(F(" hdop="));
Serial.println(gps.hdop.hdop());
}
else if (millis() - last > 5000)
{
Serial.println();
if (gps.location.isValid())
{
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
double distanceToLondon =
TinyGPSPlus::distanceBetween(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);
double courseToLondon =
TinyGPSPlus::courseTo(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);
Serial.print(F("LONDON Distance="));
Serial.print(distanceToLondon/1000, 6);
Serial.print(F(" km Course-to="));
Serial.print(courseToLondon, 6);
Serial.print(F(" degrees ["));
Serial.print(TinyGPSPlus::cardinal(courseToLondon));
Serial.println(F("]"));
}
Serial.print(F("DIAGS Chars="));
Serial.print(gps.charsProcessed());
Serial.print(F(" Sentences-with-Fix="));
Serial.print(gps.sentencesWithFix());
Serial.print(F(" Failed-checksum="));
Serial.print(gps.failedChecksum());
Serial.print(F(" Passed-checksum="));
Serial.println(gps.passedChecksum());
if (gps.charsProcessed() < 10)
Serial.println(F("WARNING: No GPS data. Check wiring."));
last = millis();
Serial.println();
}
}

View File

@@ -0,0 +1,150 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample code tracks satellite elevations using TinyGPSCustom objects.
Satellite numbers and elevations are not normally tracked by TinyGPS++, but
by using TinyGPSCustom we get around this.
It requires the use of SoftwareSerial and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(RX) and 3(TX).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
static const int MAX_SATELLITES = 40;
static const int PAGE_LENGTH = 40;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
TinyGPSCustom totalGPGSVMessages(gps, "GPGSV", 1); // $GPGSV sentence, first element
TinyGPSCustom messageNumber(gps, "GPGSV", 2); // $GPGSV sentence, second element
TinyGPSCustom satNumber[4]; // to be initialized later
TinyGPSCustom elevation[4];
bool anyChanges = false;
unsigned long linecount = 0;
struct
{
int elevation;
bool active;
} sats[MAX_SATELLITES];
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("SatElevTracker.ino"));
Serial.println(F("Displays GPS satellite elevations as they change"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
// Initialize all the uninitialized TinyGPSCustom objects
for (int i=0; i<4; ++i)
{
satNumber[i].begin(gps, "GPGSV", 4 + 4 * i); // offsets 4, 8, 12, 16
elevation[i].begin(gps, "GPGSV", 5 + 4 * i); // offsets 5, 9, 13, 17
}
}
void loop()
{
// Dispatch incoming characters
if (ss.available() > 0)
{
gps.encode(ss.read());
if (totalGPGSVMessages.isUpdated())
{
for (int i=0; i<4; ++i)
{
int no = atoi(satNumber[i].value());
if (no >= 1 && no <= MAX_SATELLITES)
{
int elev = atoi(elevation[i].value());
sats[no-1].active = true;
if (sats[no-1].elevation != elev)
{
sats[no-1].elevation = elev;
anyChanges = true;
}
}
}
int totalMessages = atoi(totalGPGSVMessages.value());
int currentMessage = atoi(messageNumber.value());
if (totalMessages == currentMessage && anyChanges)
{
if (linecount++ % PAGE_LENGTH == 0)
printHeader();
TimePrint();
for (int i=0; i<MAX_SATELLITES; ++i)
{
Serial.print(F(" "));
if (sats[i].active)
IntPrint(sats[i].elevation, 2);
else
Serial.print(F(" "));
sats[i].active = false;
}
Serial.println();
anyChanges = false;
}
}
}
}
void IntPrint(int n, int len)
{
int digs = n < 0 ? 2 : 1;
for (int i=10; i<=abs(n); i*=10)
++digs;
while (digs++ < len)
Serial.print(F(" "));
Serial.print(n);
Serial.print(F(" "));
}
void TimePrint()
{
if (gps.time.isValid())
{
if (gps.time.hour() < 10)
Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10)
Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10)
Serial.print(F("0"));
Serial.print(gps.time.second());
Serial.print(F(" "));
}
else
{
Serial.print(F("(unknown)"));
}
}
void printHeader()
{
Serial.println();
Serial.print(F("Time "));
for (int i=0; i<MAX_SATELLITES; ++i)
{
Serial.print(F(" "));
IntPrint(i+1, 2);
}
Serial.println();
Serial.print(F("---------"));
for (int i=0; i<MAX_SATELLITES; ++i)
Serial.print(F("----"));
Serial.println();
}

View File

@@ -0,0 +1,149 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample code demonstrates how to use an array of TinyGPSCustom objects
to monitor all the visible satellites.
Satellite numbers, elevation, azimuth, and signal-to-noise ratio are not
normally tracked by TinyGPS++, but by using TinyGPSCustom we get around this.
The simple code also demonstrates how to use arrays of TinyGPSCustom objects,
each monitoring a different field of the $GPGSV sentence.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(RX) and 3(TX).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
/*
From http://aprs.gids.nl/nmea/:
$GPGSV
GPS Satellites in view
eg. $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74
$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D
1 = Total number of messages of this type in this cycle
2 = Message number
3 = Total number of SVs in view
4 = SV PRN number
5 = Elevation in degrees, 90 maximum
6 = Azimuth, degrees from true north, 000 to 359
7 = SNR, 00-99 dB (null when not tracking)
8-11 = Information about second SV, same as field 4-7
12-15= Information about third SV, same as field 4-7
16-19= Information about fourth SV, same as field 4-7
*/
static const int MAX_SATELLITES = 40;
TinyGPSCustom totalGPGSVMessages(gps, "GPGSV", 1); // $GPGSV sentence, first element
TinyGPSCustom messageNumber(gps, "GPGSV", 2); // $GPGSV sentence, second element
TinyGPSCustom satsInView(gps, "GPGSV", 3); // $GPGSV sentence, third element
TinyGPSCustom satNumber[4]; // to be initialized later
TinyGPSCustom elevation[4];
TinyGPSCustom azimuth[4];
TinyGPSCustom snr[4];
struct
{
bool active;
int elevation;
int azimuth;
int snr;
} sats[MAX_SATELLITES];
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("SatelliteTracker.ino"));
Serial.println(F("Monitoring satellite location and signal strength using TinyGPSCustom"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
// Initialize all the uninitialized TinyGPSCustom objects
for (int i=0; i<4; ++i)
{
satNumber[i].begin(gps, "GPGSV", 4 + 4 * i); // offsets 4, 8, 12, 16
elevation[i].begin(gps, "GPGSV", 5 + 4 * i); // offsets 5, 9, 13, 17
azimuth[i].begin( gps, "GPGSV", 6 + 4 * i); // offsets 6, 10, 14, 18
snr[i].begin( gps, "GPGSV", 7 + 4 * i); // offsets 7, 11, 15, 19
}
}
void loop()
{
// Dispatch incoming characters
if (ss.available() > 0)
{
gps.encode(ss.read());
if (totalGPGSVMessages.isUpdated())
{
for (int i=0; i<4; ++i)
{
int no = atoi(satNumber[i].value());
// Serial.print(F("SatNumber is ")); Serial.println(no);
if (no >= 1 && no <= MAX_SATELLITES)
{
sats[no-1].elevation = atoi(elevation[i].value());
sats[no-1].azimuth = atoi(azimuth[i].value());
sats[no-1].snr = atoi(snr[i].value());
sats[no-1].active = true;
}
}
int totalMessages = atoi(totalGPGSVMessages.value());
int currentMessage = atoi(messageNumber.value());
if (totalMessages == currentMessage)
{
Serial.print(F("Sats=")); Serial.print(gps.satellites.value());
Serial.print(F(" Nums="));
for (int i=0; i<MAX_SATELLITES; ++i)
if (sats[i].active)
{
Serial.print(i+1);
Serial.print(F(" "));
}
Serial.print(F(" Elevation="));
for (int i=0; i<MAX_SATELLITES; ++i)
if (sats[i].active)
{
Serial.print(sats[i].elevation);
Serial.print(F(" "));
}
Serial.print(F(" Azimuth="));
for (int i=0; i<MAX_SATELLITES; ++i)
if (sats[i].active)
{
Serial.print(sats[i].azimuth);
Serial.print(F(" "));
}
Serial.print(F(" SNR="));
for (int i=0; i<MAX_SATELLITES; ++i)
if (sats[i].active)
{
Serial.print(sats[i].snr);
Serial.print(F(" "));
}
Serial.println();
for (int i=0; i<MAX_SATELLITES; ++i)
sats[i].active = false;
}
}
}
}

View File

@@ -0,0 +1,69 @@
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample demonstrates TinyGPS++'s capacity for extracting custom
fields from any NMEA sentence. TinyGPS++ has built-in facilities for
extracting latitude, longitude, altitude, etc., from the $GPGGA and
$GPRMC sentences. But with the TinyGPSCustom type, you can extract
other NMEA fields, even from non-standard NMEA sentences.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(RX) and 3(TX).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
/*
By declaring TinyGPSCustom objects like this, we announce that we
are interested in the 15th, 16th, and 17th fields in the $GPGSA
sentence, respectively the PDOP (F("positional dilution of precision")),
HDOP (F("horizontal...")), and VDOP (F("vertical...")).
(Counting starts with the field immediately following the sentence name,
i.e. $GPGSA. For more information on NMEA sentences, consult your
GPS module's documentation and/or http://aprs.gids.nl/nmea/.)
If your GPS module doesn't support the $GPGSA sentence, then you
won't get any output from this program.
*/
TinyGPSCustom pdop(gps, "GPGSA", 15); // $GPGSA sentence, 15th element
TinyGPSCustom hdop(gps, "GPGSA", 16); // $GPGSA sentence, 16th element
TinyGPSCustom vdop(gps, "GPGSA", 17); // $GPGSA sentence, 17th element
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("UsingCustomFields.ino"));
Serial.println(F("Demonstrating how to extract any NMEA field using TinyGPSCustom"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
}
void loop()
{
// Every time anything is updated, print everything.
if (gps.altitude.isUpdated() || gps.satellites.isUpdated() ||
pdop.isUpdated() || hdop.isUpdated() || vdop.isUpdated())
{
Serial.print(F("ALT=")); Serial.print(gps.altitude.meters());
Serial.print(F(" PDOP=")); Serial.print(pdop.value());
Serial.print(F(" HDOP=")); Serial.print(hdop.value());
Serial.print(F(" VDOP=")); Serial.print(vdop.value());
Serial.print(F(" SATS=")); Serial.println(gps.satellites.value());
}
while (ss.available() > 0)
gps.encode(ss.read());
}

View File

@@ -0,0 +1,71 @@
#######################################
# Syntax Coloring Map for TinyGPS++
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
TinyGPSPlus KEYWORD1
TinyGPSLocation KEYWORD1
TinyGPSDate KEYWORD1
TinyGPSTime KEYWORD1
TinyGPSSpeed KEYWORD1
TinyGPSCourse KEYWORD1
TinyGPSAltitude KEYWORD1
TinyGPSInteger KEYWORD1
TinyGPSDecimal KEYWORD1
TinyGPSCustom KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
encode KEYWORD2
location KEYWORD2
date KEYWORD2
time KEYWORD2
speed KEYWORD2
course KEYWORD2
altitude KEYWORD2
satellites KEYWORD2
hdop KEYWORD2
libraryVersion KEYWORD2
distanceBetween KEYWORD2
courseTo KEYWORD2
cardinal KEYWORD2
charsProcessed KEYWORD2
sentencesWithFix KEYWORD2
failedChecksum KEYWORD2
passedChecksum KEYWORD2
isValid KEYWORD2
isUpdated KEYWORD2
age KEYWORD2
lat KEYWORD2
lng KEYWORD2
isUpdatedDate KEYWORD2
isUpdatedTime KEYWORD2
year KEYWORD2
month KEYWORD2
day KEYWORD2
hour KEYWORD2
minute KEYWORD2
second KEYWORD2
centisecond KEYWORD2
value KEYWORD2
knots KEYWORD2
mph KEYWORD2
mps KEYWORD2
kmph KEYWORD2
deg KEYWORD2
billionths KEYWORD2
negative KEYWORD2
meters KEYWORD2
miles KEYWORD2
kilometers KEYWORD2
feet KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,22 @@
{
"name": "TinyGPSPlus",
"version": "1.0.2",
"keywords": "gps,NMEA",
"description": "A new, customizable Arduino NMEA parsing library",
"repository":
{
"type": "git",
"url": "https://github.com/mikalhart/TinyGPSPlus.git"
},
"authors":
[
{
"name": "Mikal Hart",
"email": "mikal@arduniana.org",
"url": "http://arduiniana.org",
"maintainer": true
}
],
"frameworks": "arduino",
"platforms": "*"
}

View File

@@ -0,0 +1,9 @@
name=TinyGPS++
version=1.0.0
author=Mikal Hart
maintainer=Mikal Hart<mikal@arduniana.org>
sentence=TinyGPS++ provides object-oriented parsing of GPS (NMEA) sentences
paragraph=NMEA is the standard format GPS devices use to report location, time, altitude, etc. TinyGPS++ is a compact, resilient library that parses the most common NMEA 'sentences' used: GGA and RMC. It can also be customized to extract data from *any* compliant sentence.
category=Communication
url=https://github.com/mikalhart/TinyGPSPlus
architectures=*

View File

@@ -0,0 +1,503 @@
/*
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Location precision improvements suggested by Wayne Holder.
Copyright (C) 2008-2013 Mikal Hart
All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "TinyGPS++.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define _GPRMCterm "GPRMC"
#define _GPGGAterm "GPGGA"
#define _GNRMCterm "GNRMC"
#define _GNGGAterm "GNGGA"
TinyGPSPlus::TinyGPSPlus()
: parity(0)
, isChecksumTerm(false)
, curSentenceType(GPS_SENTENCE_OTHER)
, curTermNumber(0)
, curTermOffset(0)
, sentenceHasFix(false)
, customElts(0)
, customCandidates(0)
, encodedCharCount(0)
, sentencesWithFixCount(0)
, failedChecksumCount(0)
, passedChecksumCount(0)
{
term[0] = '\0';
}
//
// public methods
//
bool TinyGPSPlus::encode(char c)
{
++encodedCharCount;
switch(c)
{
case ',': // term terminators
parity ^= (uint8_t)c;
case '\r':
case '\n':
case '*':
{
bool isValidSentence = false;
if (curTermOffset < sizeof(term))
{
term[curTermOffset] = 0;
isValidSentence = endOfTermHandler();
}
++curTermNumber;
curTermOffset = 0;
isChecksumTerm = c == '*';
return isValidSentence;
}
break;
case '$': // sentence begin
curTermNumber = curTermOffset = 0;
parity = 0;
curSentenceType = GPS_SENTENCE_OTHER;
isChecksumTerm = false;
sentenceHasFix = false;
return false;
default: // ordinary characters
if (curTermOffset < sizeof(term) - 1)
term[curTermOffset++] = c;
if (!isChecksumTerm)
parity ^= c;
return false;
}
return false;
}
//
// internal utilities
//
int TinyGPSPlus::fromHex(char a)
{
if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
else
return a - '0';
}
// static
// Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
int32_t TinyGPSPlus::parseDecimal(const char *term)
{
bool negative = *term == '-';
if (negative) ++term;
int32_t ret = 100 * (int32_t)atol(term);
while (isdigit(*term)) ++term;
if (*term == '.' && isdigit(term[1]))
{
ret += 10 * (term[1] - '0');
if (isdigit(term[2]))
ret += term[2] - '0';
}
return negative ? -ret : ret;
}
// static
// Parse degrees in that funny NMEA format DDMM.MMMM
void TinyGPSPlus::parseDegrees(const char *term, RawDegrees &deg)
{
uint32_t leftOfDecimal = (uint32_t)atol(term);
uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
uint32_t multiplier = 10000000UL;
uint32_t tenMillionthsOfMinutes = minutes * multiplier;
deg.deg = (int16_t)(leftOfDecimal / 100);
while (isdigit(*term))
++term;
if (*term == '.')
while (isdigit(*++term))
{
multiplier /= 10;
tenMillionthsOfMinutes += (*term - '0') * multiplier;
}
deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
deg.negative = false;
}
#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
// Processes a just-completed term
// Returns true if new sentence has just passed checksum test and is validated
bool TinyGPSPlus::endOfTermHandler()
{
// If it's the checksum term, and the checksum checks out, commit
if (isChecksumTerm)
{
byte checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
if (checksum == parity)
{
passedChecksumCount++;
if (sentenceHasFix)
++sentencesWithFixCount;
switch(curSentenceType)
{
case GPS_SENTENCE_GPRMC:
date.commit();
time.commit();
if (sentenceHasFix)
{
location.commit();
speed.commit();
course.commit();
}
break;
case GPS_SENTENCE_GPGGA:
time.commit();
if (sentenceHasFix)
{
location.commit();
altitude.commit();
}
satellites.commit();
hdop.commit();
break;
}
// Commit all custom listeners of this sentence type
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
p->commit();
return true;
}
else
{
++failedChecksumCount;
}
return false;
}
// the first term determines the sentence type
if (curTermNumber == 0)
{
if (!strcmp(term, _GPRMCterm) || !strcmp(term, _GNRMCterm))
curSentenceType = GPS_SENTENCE_GPRMC;
else if (!strcmp(term, _GPGGAterm) || !strcmp(term, _GNGGAterm))
curSentenceType = GPS_SENTENCE_GPGGA;
else
curSentenceType = GPS_SENTENCE_OTHER;
// Any custom candidates of this sentence type?
for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
customCandidates = NULL;
return false;
}
if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
switch(COMBINE(curSentenceType, curTermNumber))
{
case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences
case COMBINE(GPS_SENTENCE_GPGGA, 1):
time.setTime(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
sentenceHasFix = term[0] == 'A';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
case COMBINE(GPS_SENTENCE_GPGGA, 2):
location.setLatitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
case COMBINE(GPS_SENTENCE_GPGGA, 3):
location.rawNewLatData.negative = term[0] == 'S';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
case COMBINE(GPS_SENTENCE_GPGGA, 4):
location.setLongitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W
case COMBINE(GPS_SENTENCE_GPGGA, 5):
location.rawNewLngData.negative = term[0] == 'W';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
speed.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC)
course.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC)
date.setDate(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
sentenceHasFix = term[0] > '0';
break;
case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
satellites.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP
hdop.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA)
altitude.set(term);
break;
}
// Set custom values as needed
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
if (p->termNumber == curTermNumber)
p->set(term);
return false;
}
/* static */
double TinyGPSPlus::distanceBetween(double lat1, double long1, double lat2, double long2)
{
// returns distance in meters between two positions, both specified
// as signed decimal-degrees latitude and longitude. Uses great-circle
// distance computation for hypothetical sphere of radius 6372795 meters.
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
// Courtesy of Maarten Lamers
double delta = radians(long1-long2);
double sdlong = sin(delta);
double cdlong = cos(delta);
lat1 = radians(lat1);
lat2 = radians(lat2);
double slat1 = sin(lat1);
double clat1 = cos(lat1);
double slat2 = sin(lat2);
double clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = sq(delta);
delta += sq(clat2 * sdlong);
delta = sqrt(delta);
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
return delta * 6372795;
}
double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long2)
{
// returns course in degrees (North=0, West=270) from position 1 to position 2,
// both specified as signed decimal-degrees latitude and longitude.
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
// Courtesy of Maarten Lamers
double dlon = radians(long2-long1);
lat1 = radians(lat1);
lat2 = radians(lat2);
double a1 = sin(dlon) * cos(lat2);
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
a2 = cos(lat1) * sin(lat2) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
return degrees(a2);
}
const char *TinyGPSPlus::cardinal(double course)
{
static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
int direction = (int)((course + 11.25f) / 22.5f);
return directions[direction % 16];
}
void TinyGPSLocation::commit()
{
rawLatData = rawNewLatData;
rawLngData = rawNewLngData;
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSLocation::setLatitude(const char *term)
{
TinyGPSPlus::parseDegrees(term, rawNewLatData);
}
void TinyGPSLocation::setLongitude(const char *term)
{
TinyGPSPlus::parseDegrees(term, rawNewLngData);
}
double TinyGPSLocation::lat()
{
updated = false;
double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
return rawLatData.negative ? -ret : ret;
}
double TinyGPSLocation::lng()
{
updated = false;
double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
return rawLngData.negative ? -ret : ret;
}
void TinyGPSDate::commit()
{
date = newDate;
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSTime::commit()
{
time = newTime;
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSTime::setTime(const char *term)
{
newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
}
void TinyGPSDate::setDate(const char *term)
{
newDate = atol(term);
}
uint16_t TinyGPSDate::year()
{
updated = false;
uint16_t year = date % 100;
return year + 2000;
}
uint8_t TinyGPSDate::month()
{
updated = false;
return (date / 100) % 100;
}
uint8_t TinyGPSDate::day()
{
updated = false;
return date / 10000;
}
uint8_t TinyGPSTime::hour()
{
updated = false;
return time / 1000000;
}
uint8_t TinyGPSTime::minute()
{
updated = false;
return (time / 10000) % 100;
}
uint8_t TinyGPSTime::second()
{
updated = false;
return (time / 100) % 100;
}
uint8_t TinyGPSTime::centisecond()
{
updated = false;
return time % 100;
}
void TinyGPSDecimal::commit()
{
val = newval;
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSDecimal::set(const char *term)
{
newval = TinyGPSPlus::parseDecimal(term);
}
void TinyGPSInteger::commit()
{
val = newval;
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSInteger::set(const char *term)
{
newval = atol(term);
}
TinyGPSCustom::TinyGPSCustom(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
{
begin(gps, _sentenceName, _termNumber);
}
void TinyGPSCustom::begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
{
lastCommitTime = 0;
updated = valid = false;
sentenceName = _sentenceName;
termNumber = _termNumber;
memset(stagingBuffer, '\0', sizeof(stagingBuffer));
memset(buffer, '\0', sizeof(buffer));
// Insert this item into the GPS tree
gps.insertCustom(this, _sentenceName, _termNumber);
}
void TinyGPSCustom::commit()
{
strcpy(this->buffer, this->stagingBuffer);
lastCommitTime = millis();
valid = updated = true;
}
void TinyGPSCustom::set(const char *term)
{
strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer));
}
void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
{
TinyGPSCustom **ppelt;
for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
{
int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
break;
}
pElt->next = *ppelt;
*ppelt = pElt;
}

View File

@@ -0,0 +1,278 @@
/*
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Location precision improvements suggested by Wayne Holder.
Copyright (C) 2008-2013 Mikal Hart
All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __TinyGPSPlus_h
#define __TinyGPSPlus_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <limits.h>
#define _GPS_VERSION "1.0.2" // software version of this library
#define _GPS_MPH_PER_KNOT 1.15077945
#define _GPS_MPS_PER_KNOT 0.51444444
#define _GPS_KMPH_PER_KNOT 1.852
#define _GPS_MILES_PER_METER 0.00062137112
#define _GPS_KM_PER_METER 0.001
#define _GPS_FEET_PER_METER 3.2808399
#define _GPS_MAX_FIELD_SIZE 15
struct RawDegrees
{
uint16_t deg;
uint32_t billionths;
bool negative;
public:
RawDegrees() : deg(0), billionths(0), negative(false)
{}
};
struct TinyGPSLocation
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
const RawDegrees &rawLat() { updated = false; return rawLatData; }
const RawDegrees &rawLng() { updated = false; return rawLngData; }
double lat();
double lng();
TinyGPSLocation() : valid(false), updated(false)
{}
private:
bool valid, updated;
RawDegrees rawLatData, rawLngData, rawNewLatData, rawNewLngData;
uint32_t lastCommitTime;
void commit();
void setLatitude(const char *term);
void setLongitude(const char *term);
};
struct TinyGPSDate
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return date; }
uint16_t year();
uint8_t month();
uint8_t day();
TinyGPSDate() : valid(false), updated(false), date(0)
{}
private:
bool valid, updated;
uint32_t date, newDate;
uint32_t lastCommitTime;
void commit();
void setDate(const char *term);
};
struct TinyGPSTime
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return time; }
uint8_t hour();
uint8_t minute();
uint8_t second();
uint8_t centisecond();
TinyGPSTime() : valid(false), updated(false), time(0)
{}
private:
bool valid, updated;
uint32_t time, newTime;
uint32_t lastCommitTime;
void commit();
void setTime(const char *term);
};
struct TinyGPSDecimal
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
int32_t value() { updated = false; return val; }
TinyGPSDecimal() : valid(false), updated(false), val(0)
{}
private:
bool valid, updated;
uint32_t lastCommitTime;
int32_t val, newval;
void commit();
void set(const char *term);
};
struct TinyGPSInteger
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return val; }
TinyGPSInteger() : valid(false), updated(false), val(0)
{}
private:
bool valid, updated;
uint32_t lastCommitTime;
uint32_t val, newval;
void commit();
void set(const char *term);
};
struct TinyGPSSpeed : TinyGPSDecimal
{
double knots() { return value() / 100.0; }
double mph() { return _GPS_MPH_PER_KNOT * value() / 100.0; }
double mps() { return _GPS_MPS_PER_KNOT * value() / 100.0; }
double kmph() { return _GPS_KMPH_PER_KNOT * value() / 100.0; }
};
struct TinyGPSCourse : public TinyGPSDecimal
{
double deg() { return value() / 100.0; }
};
struct TinyGPSAltitude : TinyGPSDecimal
{
double meters() { return value() / 100.0; }
double miles() { return _GPS_MILES_PER_METER * value() / 100.0; }
double kilometers() { return _GPS_KM_PER_METER * value() / 100.0; }
double feet() { return _GPS_FEET_PER_METER * value() / 100.0; }
};
struct TinyGPSHDOP : TinyGPSDecimal
{
double hdop() { return value() / 100.0; }
};
class TinyGPSPlus;
class TinyGPSCustom
{
public:
TinyGPSCustom() {};
TinyGPSCustom(TinyGPSPlus &gps, const char *sentenceName, int termNumber);
void begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber);
bool isUpdated() const { return updated; }
bool isValid() const { return valid; }
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
const char *value() { updated = false; return buffer; }
private:
void commit();
void set(const char *term);
char stagingBuffer[_GPS_MAX_FIELD_SIZE + 1];
char buffer[_GPS_MAX_FIELD_SIZE + 1];
unsigned long lastCommitTime;
bool valid, updated;
const char *sentenceName;
int termNumber;
friend class TinyGPSPlus;
TinyGPSCustom *next;
};
class TinyGPSPlus
{
public:
TinyGPSPlus();
bool encode(char c); // process one character received from GPS
TinyGPSPlus &operator << (char c) {encode(c); return *this;}
TinyGPSLocation location;
TinyGPSDate date;
TinyGPSTime time;
TinyGPSSpeed speed;
TinyGPSCourse course;
TinyGPSAltitude altitude;
TinyGPSInteger satellites;
TinyGPSHDOP hdop;
static const char *libraryVersion() { return _GPS_VERSION; }
static double distanceBetween(double lat1, double long1, double lat2, double long2);
static double courseTo(double lat1, double long1, double lat2, double long2);
static const char *cardinal(double course);
static int32_t parseDecimal(const char *term);
static void parseDegrees(const char *term, RawDegrees &deg);
uint32_t charsProcessed() const { return encodedCharCount; }
uint32_t sentencesWithFix() const { return sentencesWithFixCount; }
uint32_t failedChecksum() const { return failedChecksumCount; }
uint32_t passedChecksum() const { return passedChecksumCount; }
private:
enum {GPS_SENTENCE_GPGGA, GPS_SENTENCE_GPRMC, GPS_SENTENCE_OTHER};
// parsing state variables
uint8_t parity;
bool isChecksumTerm;
char term[_GPS_MAX_FIELD_SIZE];
uint8_t curSentenceType;
uint8_t curTermNumber;
uint8_t curTermOffset;
bool sentenceHasFix;
// custom element support
friend class TinyGPSCustom;
TinyGPSCustom *customElts;
TinyGPSCustom *customCandidates;
void insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int index);
// statistics
uint32_t encodedCharCount;
uint32_t sentencesWithFixCount;
uint32_t failedChecksumCount;
uint32_t passedChecksumCount;
// internal utilities
int fromHex(char a);
bool endOfTermHandler();
};
#endif // def(__TinyGPSPlus_h)