GPS/NMEA Parser that has been ported from Arduino to mbed tested with BufferedSerial original from here : http://arduiniana.org/libraries/tinygpsplus/

Dependents:   WNC_Pubnub_obd2b_ign_em506SoftSerial_RESETFE2 mbed_xbeetest

A Full-featured GPS/NMEA Parser that has been tested with BufferedSerial

TinyGPS++ is a library for parsing NMEA data streams provided by GPS modules. Like its predecessor, TinyGPS, this library provides compact and easy-to-use methods for extracting position, date, time, altitude, speed, and course from consumer GPS devices. However, TinyGPS++’s programmer interface is considerably simpler to use than TinyGPS,

The library can extract arbitrary data from any of the myriad NMEA sentences out there, even proprietary ones

from here : http://arduiniana.org/libraries/tinygpsplus/

Committer:
Sir_Binky
Date:
Fri Jan 22 13:30:33 2016 +0000
Revision:
1:9163a9f5fc36
Parent:
0:3407bd06cfae
added a "Binary" version of the lat and lng; Binary representation of the double;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sir_Binky 0:3407bd06cfae 1 /*
Sir_Binky 0:3407bd06cfae 2 TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
Sir_Binky 0:3407bd06cfae 3 Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Sir_Binky 0:3407bd06cfae 4 Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Sir_Binky 0:3407bd06cfae 5 Location precision improvements suggested by Wayne Holder.
Sir_Binky 0:3407bd06cfae 6 Copyright (C) 2008-2013 Mikal Hart
Sir_Binky 0:3407bd06cfae 7 All rights reserved.
Sir_Binky 0:3407bd06cfae 8
Sir_Binky 0:3407bd06cfae 9 This library is free software; you can redistribute it and/or
Sir_Binky 0:3407bd06cfae 10 modify it under the terms of the GNU Lesser General Public
Sir_Binky 0:3407bd06cfae 11 License as published by the Free Software Foundation; either
Sir_Binky 0:3407bd06cfae 12 version 2.1 of the License, or (at your option) any later version.
Sir_Binky 0:3407bd06cfae 13
Sir_Binky 0:3407bd06cfae 14 This library is distributed in the hope that it will be useful,
Sir_Binky 0:3407bd06cfae 15 but WITHOUT ANY WARRANTY; without even the implied warranty of
Sir_Binky 0:3407bd06cfae 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Sir_Binky 0:3407bd06cfae 17 Lesser General Public License for more details.
Sir_Binky 0:3407bd06cfae 18
Sir_Binky 0:3407bd06cfae 19 You should have received a copy of the GNU Lesser General Public
Sir_Binky 0:3407bd06cfae 20 License along with this library; if not, write to the Free Software
Sir_Binky 0:3407bd06cfae 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sir_Binky 0:3407bd06cfae 22
Sir_Binky 0:3407bd06cfae 23 Ported to mbed by Daniel de Kock
Sir_Binky 0:3407bd06cfae 24 */
Sir_Binky 0:3407bd06cfae 25
Sir_Binky 0:3407bd06cfae 26 #include "TinyGPSplus.h"
Sir_Binky 0:3407bd06cfae 27
Sir_Binky 0:3407bd06cfae 28 #include <string.h>
Sir_Binky 0:3407bd06cfae 29 #include <ctype.h>
Sir_Binky 0:3407bd06cfae 30 #include <stdlib.h>
Sir_Binky 0:3407bd06cfae 31
Sir_Binky 0:3407bd06cfae 32 #define _GPRMCterm "GPRMC"
Sir_Binky 0:3407bd06cfae 33 #define _GPGGAterm "GPGGA"
Sir_Binky 0:3407bd06cfae 34
Sir_Binky 0:3407bd06cfae 35 TinyGPSPlus::TinyGPSPlus()
Sir_Binky 0:3407bd06cfae 36 : parity(0)
Sir_Binky 0:3407bd06cfae 37 , isChecksumTerm(false)
Sir_Binky 0:3407bd06cfae 38 , curSentenceType(GPS_SENTENCE_OTHER)
Sir_Binky 0:3407bd06cfae 39 , curTermNumber(0)
Sir_Binky 0:3407bd06cfae 40 , curTermOffset(0)
Sir_Binky 0:3407bd06cfae 41 , sentenceHasFix(false)
Sir_Binky 0:3407bd06cfae 42 , customElts(0)
Sir_Binky 0:3407bd06cfae 43 , customCandidates(0)
Sir_Binky 0:3407bd06cfae 44 , encodedCharCount(0)
Sir_Binky 0:3407bd06cfae 45 , sentencesWithFixCount(0)
Sir_Binky 0:3407bd06cfae 46 , failedChecksumCount(0)
Sir_Binky 0:3407bd06cfae 47 , passedChecksumCount(0)
Sir_Binky 0:3407bd06cfae 48 {
Sir_Binky 0:3407bd06cfae 49 term[0] = '\0';
Sir_Binky 0:3407bd06cfae 50 }
Sir_Binky 0:3407bd06cfae 51
Sir_Binky 0:3407bd06cfae 52 //
Sir_Binky 0:3407bd06cfae 53 // public methods
Sir_Binky 0:3407bd06cfae 54 //
Sir_Binky 0:3407bd06cfae 55
Sir_Binky 0:3407bd06cfae 56 bool TinyGPSPlus::encode(char c)
Sir_Binky 0:3407bd06cfae 57 {
Sir_Binky 0:3407bd06cfae 58 ++encodedCharCount;
Sir_Binky 0:3407bd06cfae 59
Sir_Binky 0:3407bd06cfae 60 switch(c)
Sir_Binky 0:3407bd06cfae 61 {
Sir_Binky 0:3407bd06cfae 62 case ',': // term terminators
Sir_Binky 0:3407bd06cfae 63 parity ^= (uint8_t)c;
Sir_Binky 0:3407bd06cfae 64 case '\r':
Sir_Binky 0:3407bd06cfae 65 case '\n':
Sir_Binky 0:3407bd06cfae 66 case '*':
Sir_Binky 0:3407bd06cfae 67 {
Sir_Binky 0:3407bd06cfae 68 bool isValidSentence = false;
Sir_Binky 0:3407bd06cfae 69 if (curTermOffset < sizeof(term))
Sir_Binky 0:3407bd06cfae 70 {
Sir_Binky 0:3407bd06cfae 71 term[curTermOffset] = 0;
Sir_Binky 0:3407bd06cfae 72 isValidSentence = endOfTermHandler();
Sir_Binky 0:3407bd06cfae 73 }
Sir_Binky 0:3407bd06cfae 74 ++curTermNumber;
Sir_Binky 0:3407bd06cfae 75 curTermOffset = 0;
Sir_Binky 0:3407bd06cfae 76 isChecksumTerm = c == '*';
Sir_Binky 0:3407bd06cfae 77 return isValidSentence;
Sir_Binky 0:3407bd06cfae 78 }
Sir_Binky 0:3407bd06cfae 79 break;
Sir_Binky 0:3407bd06cfae 80
Sir_Binky 0:3407bd06cfae 81 case '$': // sentence begin
Sir_Binky 0:3407bd06cfae 82 curTermNumber = curTermOffset = 0;
Sir_Binky 0:3407bd06cfae 83 parity = 0;
Sir_Binky 0:3407bd06cfae 84 curSentenceType = GPS_SENTENCE_OTHER;
Sir_Binky 0:3407bd06cfae 85 isChecksumTerm = false;
Sir_Binky 0:3407bd06cfae 86 sentenceHasFix = false;
Sir_Binky 0:3407bd06cfae 87 return false;
Sir_Binky 0:3407bd06cfae 88
Sir_Binky 0:3407bd06cfae 89 default: // ordinary characters
Sir_Binky 0:3407bd06cfae 90 if (curTermOffset < sizeof(term) - 1)
Sir_Binky 0:3407bd06cfae 91 term[curTermOffset++] = c;
Sir_Binky 0:3407bd06cfae 92 if (!isChecksumTerm)
Sir_Binky 0:3407bd06cfae 93 parity ^= c;
Sir_Binky 0:3407bd06cfae 94 return false;
Sir_Binky 0:3407bd06cfae 95 }
Sir_Binky 0:3407bd06cfae 96
Sir_Binky 0:3407bd06cfae 97 return false;
Sir_Binky 0:3407bd06cfae 98 }
Sir_Binky 0:3407bd06cfae 99
Sir_Binky 0:3407bd06cfae 100 //
Sir_Binky 0:3407bd06cfae 101 // internal utilities
Sir_Binky 0:3407bd06cfae 102 //
Sir_Binky 0:3407bd06cfae 103 int TinyGPSPlus::fromHex(char a)
Sir_Binky 0:3407bd06cfae 104 {
Sir_Binky 0:3407bd06cfae 105 if (a >= 'A' && a <= 'F')
Sir_Binky 0:3407bd06cfae 106 return a - 'A' + 10;
Sir_Binky 0:3407bd06cfae 107 else if (a >= 'a' && a <= 'f')
Sir_Binky 0:3407bd06cfae 108 return a - 'a' + 10;
Sir_Binky 0:3407bd06cfae 109 else
Sir_Binky 0:3407bd06cfae 110 return a - '0';
Sir_Binky 0:3407bd06cfae 111 }
Sir_Binky 0:3407bd06cfae 112
Sir_Binky 0:3407bd06cfae 113 // static
Sir_Binky 0:3407bd06cfae 114 // Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
Sir_Binky 0:3407bd06cfae 115 int32_t TinyGPSPlus::parseDecimal(const char *term)
Sir_Binky 0:3407bd06cfae 116 {
Sir_Binky 0:3407bd06cfae 117 bool negative = *term == '-';
Sir_Binky 0:3407bd06cfae 118 if (negative) ++term;
Sir_Binky 0:3407bd06cfae 119 int32_t ret = 100 * (int32_t)atol(term);
Sir_Binky 0:3407bd06cfae 120 while (isdigit(*term)) ++term;
Sir_Binky 0:3407bd06cfae 121 if (*term == '.' && isdigit(term[1]))
Sir_Binky 0:3407bd06cfae 122 {
Sir_Binky 0:3407bd06cfae 123 ret += 10 * (term[1] - '0');
Sir_Binky 0:3407bd06cfae 124 if (isdigit(term[2]))
Sir_Binky 0:3407bd06cfae 125 ret += term[2] - '0';
Sir_Binky 0:3407bd06cfae 126 }
Sir_Binky 0:3407bd06cfae 127 return negative ? -ret : ret;
Sir_Binky 0:3407bd06cfae 128 }
Sir_Binky 0:3407bd06cfae 129
Sir_Binky 0:3407bd06cfae 130 // static
Sir_Binky 0:3407bd06cfae 131 // Parse degrees in that funny NMEA format DDMM.MMMM
Sir_Binky 0:3407bd06cfae 132 void TinyGPSPlus::parseDegrees(const char *term, RawDegrees &deg)
Sir_Binky 0:3407bd06cfae 133 {
Sir_Binky 0:3407bd06cfae 134 uint32_t leftOfDecimal = (uint32_t)atol(term);
Sir_Binky 0:3407bd06cfae 135 uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
Sir_Binky 0:3407bd06cfae 136 uint32_t multiplier = 10000000UL;
Sir_Binky 0:3407bd06cfae 137 uint32_t tenMillionthsOfMinutes = minutes * multiplier;
Sir_Binky 0:3407bd06cfae 138
Sir_Binky 0:3407bd06cfae 139 deg.deg = (int16_t)(leftOfDecimal / 100);
Sir_Binky 0:3407bd06cfae 140
Sir_Binky 0:3407bd06cfae 141 while (isdigit(*term))
Sir_Binky 0:3407bd06cfae 142 ++term;
Sir_Binky 0:3407bd06cfae 143
Sir_Binky 0:3407bd06cfae 144 if (*term == '.')
Sir_Binky 0:3407bd06cfae 145 while (isdigit(*++term))
Sir_Binky 0:3407bd06cfae 146 {
Sir_Binky 0:3407bd06cfae 147 multiplier /= 10;
Sir_Binky 0:3407bd06cfae 148 tenMillionthsOfMinutes += (*term - '0') * multiplier;
Sir_Binky 0:3407bd06cfae 149 }
Sir_Binky 0:3407bd06cfae 150
Sir_Binky 0:3407bd06cfae 151 deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
Sir_Binky 0:3407bd06cfae 152 deg.negative = false;
Sir_Binky 0:3407bd06cfae 153 }
Sir_Binky 0:3407bd06cfae 154
Sir_Binky 0:3407bd06cfae 155 #define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
Sir_Binky 0:3407bd06cfae 156
Sir_Binky 0:3407bd06cfae 157 // Processes a just-completed term
Sir_Binky 0:3407bd06cfae 158 // Returns true if new sentence has just passed checksum test and is validated
Sir_Binky 0:3407bd06cfae 159 bool TinyGPSPlus::endOfTermHandler()
Sir_Binky 0:3407bd06cfae 160 {
Sir_Binky 0:3407bd06cfae 161 // If it's the checksum term, and the checksum checks out, commit
Sir_Binky 0:3407bd06cfae 162 if (isChecksumTerm)
Sir_Binky 0:3407bd06cfae 163 {
Sir_Binky 0:3407bd06cfae 164 byte checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
Sir_Binky 0:3407bd06cfae 165 if (checksum == parity)
Sir_Binky 0:3407bd06cfae 166 {
Sir_Binky 0:3407bd06cfae 167 passedChecksumCount++;
Sir_Binky 0:3407bd06cfae 168 if (sentenceHasFix)
Sir_Binky 0:3407bd06cfae 169 ++sentencesWithFixCount;
Sir_Binky 0:3407bd06cfae 170
Sir_Binky 0:3407bd06cfae 171 switch(curSentenceType)
Sir_Binky 0:3407bd06cfae 172 {
Sir_Binky 0:3407bd06cfae 173 case GPS_SENTENCE_GPRMC:
Sir_Binky 0:3407bd06cfae 174 date.commit();
Sir_Binky 0:3407bd06cfae 175 time.commit();
Sir_Binky 0:3407bd06cfae 176 if (sentenceHasFix)
Sir_Binky 0:3407bd06cfae 177 {
Sir_Binky 0:3407bd06cfae 178 location.commit();
Sir_Binky 0:3407bd06cfae 179 speed.commit();
Sir_Binky 0:3407bd06cfae 180 course.commit();
Sir_Binky 0:3407bd06cfae 181 }
Sir_Binky 0:3407bd06cfae 182 break;
Sir_Binky 0:3407bd06cfae 183 case GPS_SENTENCE_GPGGA:
Sir_Binky 0:3407bd06cfae 184 time.commit();
Sir_Binky 0:3407bd06cfae 185 if (sentenceHasFix)
Sir_Binky 0:3407bd06cfae 186 {
Sir_Binky 0:3407bd06cfae 187 location.commit();
Sir_Binky 0:3407bd06cfae 188 altitude.commit();
Sir_Binky 0:3407bd06cfae 189 }
Sir_Binky 0:3407bd06cfae 190 satellites.commit();
Sir_Binky 0:3407bd06cfae 191 hdop.commit();
Sir_Binky 0:3407bd06cfae 192 break;
Sir_Binky 0:3407bd06cfae 193 }
Sir_Binky 0:3407bd06cfae 194
Sir_Binky 0:3407bd06cfae 195 // Commit all custom listeners of this sentence type
Sir_Binky 0:3407bd06cfae 196 for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
Sir_Binky 0:3407bd06cfae 197 p->commit();
Sir_Binky 0:3407bd06cfae 198 return true;
Sir_Binky 0:3407bd06cfae 199 }
Sir_Binky 0:3407bd06cfae 200
Sir_Binky 0:3407bd06cfae 201 else
Sir_Binky 0:3407bd06cfae 202 {
Sir_Binky 0:3407bd06cfae 203 ++failedChecksumCount;
Sir_Binky 0:3407bd06cfae 204 }
Sir_Binky 0:3407bd06cfae 205
Sir_Binky 0:3407bd06cfae 206 return false;
Sir_Binky 0:3407bd06cfae 207 }
Sir_Binky 0:3407bd06cfae 208
Sir_Binky 0:3407bd06cfae 209 // the first term determines the sentence type
Sir_Binky 0:3407bd06cfae 210 if (curTermNumber == 0)
Sir_Binky 0:3407bd06cfae 211 {
Sir_Binky 0:3407bd06cfae 212 if (!strcmp(term, _GPRMCterm))
Sir_Binky 0:3407bd06cfae 213 curSentenceType = GPS_SENTENCE_GPRMC;
Sir_Binky 0:3407bd06cfae 214 else if (!strcmp(term, _GPGGAterm))
Sir_Binky 0:3407bd06cfae 215 curSentenceType = GPS_SENTENCE_GPGGA;
Sir_Binky 0:3407bd06cfae 216 else
Sir_Binky 0:3407bd06cfae 217 curSentenceType = GPS_SENTENCE_OTHER;
Sir_Binky 0:3407bd06cfae 218
Sir_Binky 0:3407bd06cfae 219 // Any custom candidates of this sentence type?
Sir_Binky 0:3407bd06cfae 220 for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
Sir_Binky 0:3407bd06cfae 221 if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
Sir_Binky 0:3407bd06cfae 222 customCandidates = NULL;
Sir_Binky 0:3407bd06cfae 223
Sir_Binky 0:3407bd06cfae 224 return false;
Sir_Binky 0:3407bd06cfae 225 }
Sir_Binky 0:3407bd06cfae 226
Sir_Binky 0:3407bd06cfae 227 if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
Sir_Binky 0:3407bd06cfae 228 switch(COMBINE(curSentenceType, curTermNumber))
Sir_Binky 0:3407bd06cfae 229 {
Sir_Binky 0:3407bd06cfae 230 case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences
Sir_Binky 0:3407bd06cfae 231 case COMBINE(GPS_SENTENCE_GPGGA, 1):
Sir_Binky 0:3407bd06cfae 232 time.setTime(term);
Sir_Binky 0:3407bd06cfae 233 break;
Sir_Binky 0:3407bd06cfae 234 case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
Sir_Binky 0:3407bd06cfae 235 sentenceHasFix = term[0] == 'A';
Sir_Binky 0:3407bd06cfae 236 break;
Sir_Binky 0:3407bd06cfae 237 case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
Sir_Binky 0:3407bd06cfae 238 case COMBINE(GPS_SENTENCE_GPGGA, 2):
Sir_Binky 0:3407bd06cfae 239 location.setLatitude(term);
Sir_Binky 0:3407bd06cfae 240 break;
Sir_Binky 0:3407bd06cfae 241 case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
Sir_Binky 0:3407bd06cfae 242 case COMBINE(GPS_SENTENCE_GPGGA, 3):
Sir_Binky 0:3407bd06cfae 243 location.rawNewLatData.negative = term[0] == 'S';
Sir_Binky 0:3407bd06cfae 244 break;
Sir_Binky 0:3407bd06cfae 245 case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
Sir_Binky 0:3407bd06cfae 246 case COMBINE(GPS_SENTENCE_GPGGA, 4):
Sir_Binky 0:3407bd06cfae 247 location.setLongitude(term);
Sir_Binky 0:3407bd06cfae 248 break;
Sir_Binky 0:3407bd06cfae 249 case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W
Sir_Binky 0:3407bd06cfae 250 case COMBINE(GPS_SENTENCE_GPGGA, 5):
Sir_Binky 0:3407bd06cfae 251 location.rawNewLngData.negative = term[0] == 'W';
Sir_Binky 0:3407bd06cfae 252 break;
Sir_Binky 0:3407bd06cfae 253 case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
Sir_Binky 0:3407bd06cfae 254 speed.set(term);
Sir_Binky 0:3407bd06cfae 255 break;
Sir_Binky 0:3407bd06cfae 256 case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC)
Sir_Binky 0:3407bd06cfae 257 course.set(term);
Sir_Binky 0:3407bd06cfae 258 break;
Sir_Binky 0:3407bd06cfae 259 case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC)
Sir_Binky 0:3407bd06cfae 260 date.setDate(term);
Sir_Binky 0:3407bd06cfae 261 break;
Sir_Binky 0:3407bd06cfae 262 case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
Sir_Binky 0:3407bd06cfae 263 sentenceHasFix = term[0] > '0';
Sir_Binky 0:3407bd06cfae 264 break;
Sir_Binky 0:3407bd06cfae 265 case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
Sir_Binky 0:3407bd06cfae 266 satellites.set(term);
Sir_Binky 0:3407bd06cfae 267 break;
Sir_Binky 0:3407bd06cfae 268 case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP
Sir_Binky 0:3407bd06cfae 269 hdop.set(term);
Sir_Binky 0:3407bd06cfae 270 break;
Sir_Binky 0:3407bd06cfae 271 case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA)
Sir_Binky 0:3407bd06cfae 272 altitude.set(term);
Sir_Binky 0:3407bd06cfae 273 break;
Sir_Binky 0:3407bd06cfae 274 }
Sir_Binky 0:3407bd06cfae 275
Sir_Binky 0:3407bd06cfae 276 // Set custom values as needed
Sir_Binky 0:3407bd06cfae 277 for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
Sir_Binky 0:3407bd06cfae 278 if (p->termNumber == curTermNumber)
Sir_Binky 0:3407bd06cfae 279 p->set(term);
Sir_Binky 0:3407bd06cfae 280
Sir_Binky 0:3407bd06cfae 281 return false;
Sir_Binky 0:3407bd06cfae 282 }
Sir_Binky 0:3407bd06cfae 283
Sir_Binky 0:3407bd06cfae 284 /* static */
Sir_Binky 0:3407bd06cfae 285 double TinyGPSPlus::distanceBetween(double lat1, double long1, double lat2, double long2)
Sir_Binky 0:3407bd06cfae 286 {
Sir_Binky 0:3407bd06cfae 287 // returns distance in meters between two positions, both specified
Sir_Binky 0:3407bd06cfae 288 // as signed decimal-degrees latitude and longitude. Uses great-circle
Sir_Binky 0:3407bd06cfae 289 // distance computation for hypothetical sphere of radius 6372795 meters.
Sir_Binky 0:3407bd06cfae 290 // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
Sir_Binky 0:3407bd06cfae 291 // Courtesy of Maarten Lamers
Sir_Binky 0:3407bd06cfae 292 double delta = radians(long1-long2);
Sir_Binky 0:3407bd06cfae 293 double sdlong = sin(delta);
Sir_Binky 0:3407bd06cfae 294 double cdlong = cos(delta);
Sir_Binky 0:3407bd06cfae 295 lat1 = radians(lat1);
Sir_Binky 0:3407bd06cfae 296 lat2 = radians(lat2);
Sir_Binky 0:3407bd06cfae 297 double slat1 = sin(lat1);
Sir_Binky 0:3407bd06cfae 298 double clat1 = cos(lat1);
Sir_Binky 0:3407bd06cfae 299 double slat2 = sin(lat2);
Sir_Binky 0:3407bd06cfae 300 double clat2 = cos(lat2);
Sir_Binky 0:3407bd06cfae 301 delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
Sir_Binky 0:3407bd06cfae 302 delta = sq(delta);
Sir_Binky 0:3407bd06cfae 303 delta += sq(clat2 * sdlong);
Sir_Binky 0:3407bd06cfae 304 delta = sqrt(delta);
Sir_Binky 0:3407bd06cfae 305 double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
Sir_Binky 0:3407bd06cfae 306 delta = atan2(delta, denom);
Sir_Binky 0:3407bd06cfae 307 return delta * 6372795;
Sir_Binky 0:3407bd06cfae 308 }
Sir_Binky 0:3407bd06cfae 309
Sir_Binky 0:3407bd06cfae 310 double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long2)
Sir_Binky 0:3407bd06cfae 311 {
Sir_Binky 0:3407bd06cfae 312 // returns course in degrees (North=0, West=270) from position 1 to position 2,
Sir_Binky 0:3407bd06cfae 313 // both specified as signed decimal-degrees latitude and longitude.
Sir_Binky 0:3407bd06cfae 314 // Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
Sir_Binky 0:3407bd06cfae 315 // Courtesy of Maarten Lamers
Sir_Binky 0:3407bd06cfae 316 double dlon = radians(long2-long1);
Sir_Binky 0:3407bd06cfae 317 lat1 = radians(lat1);
Sir_Binky 0:3407bd06cfae 318 lat2 = radians(lat2);
Sir_Binky 0:3407bd06cfae 319 double a1 = sin(dlon) * cos(lat2);
Sir_Binky 0:3407bd06cfae 320 double a2 = sin(lat1) * cos(lat2) * cos(dlon);
Sir_Binky 0:3407bd06cfae 321 a2 = cos(lat1) * sin(lat2) - a2;
Sir_Binky 0:3407bd06cfae 322 a2 = atan2(a1, a2);
Sir_Binky 0:3407bd06cfae 323 if (a2 < 0.0)
Sir_Binky 0:3407bd06cfae 324 {
Sir_Binky 0:3407bd06cfae 325 a2 += TWO_PI;
Sir_Binky 0:3407bd06cfae 326 }
Sir_Binky 0:3407bd06cfae 327 return degrees(a2);
Sir_Binky 0:3407bd06cfae 328 }
Sir_Binky 0:3407bd06cfae 329
Sir_Binky 0:3407bd06cfae 330 const char *TinyGPSPlus::cardinal(double course)
Sir_Binky 0:3407bd06cfae 331 {
Sir_Binky 0:3407bd06cfae 332 static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
Sir_Binky 0:3407bd06cfae 333 int direction = (int)((course + 11.25f) / 22.5f);
Sir_Binky 0:3407bd06cfae 334 return directions[direction % 16];
Sir_Binky 0:3407bd06cfae 335 }
Sir_Binky 0:3407bd06cfae 336
Sir_Binky 0:3407bd06cfae 337 void TinyGPSLocation::commit()
Sir_Binky 0:3407bd06cfae 338 {
Sir_Binky 0:3407bd06cfae 339 rawLatData = rawNewLatData;
Sir_Binky 0:3407bd06cfae 340 rawLngData = rawNewLngData;
Sir_Binky 0:3407bd06cfae 341 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 342 valid = updated = true;
Sir_Binky 0:3407bd06cfae 343 }
Sir_Binky 0:3407bd06cfae 344
Sir_Binky 0:3407bd06cfae 345 void TinyGPSLocation::setLatitude(const char *term)
Sir_Binky 0:3407bd06cfae 346 {
Sir_Binky 0:3407bd06cfae 347 TinyGPSPlus::parseDegrees(term, rawNewLatData);
Sir_Binky 0:3407bd06cfae 348 }
Sir_Binky 0:3407bd06cfae 349
Sir_Binky 0:3407bd06cfae 350 void TinyGPSLocation::setLongitude(const char *term)
Sir_Binky 0:3407bd06cfae 351 {
Sir_Binky 0:3407bd06cfae 352 TinyGPSPlus::parseDegrees(term, rawNewLngData);
Sir_Binky 0:3407bd06cfae 353 }
Sir_Binky 0:3407bd06cfae 354
Sir_Binky 0:3407bd06cfae 355 double TinyGPSLocation::lat()
Sir_Binky 0:3407bd06cfae 356 {
Sir_Binky 0:3407bd06cfae 357 updated = false;
Sir_Binky 0:3407bd06cfae 358 double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
Sir_Binky 0:3407bd06cfae 359 return rawLatData.negative ? -ret : ret;
Sir_Binky 0:3407bd06cfae 360 }
Sir_Binky 0:3407bd06cfae 361
Sir_Binky 0:3407bd06cfae 362 double TinyGPSLocation::lng()
Sir_Binky 0:3407bd06cfae 363 {
Sir_Binky 0:3407bd06cfae 364 updated = false;
Sir_Binky 0:3407bd06cfae 365 double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
Sir_Binky 0:3407bd06cfae 366 return rawLngData.negative ? -ret : ret;
Sir_Binky 0:3407bd06cfae 367 }
Sir_Binky 0:3407bd06cfae 368
Sir_Binky 1:9163a9f5fc36 369 int32_t TinyGPSLocation::latBinary()
Sir_Binky 1:9163a9f5fc36 370 {
Sir_Binky 1:9163a9f5fc36 371 int32_t ret;
Sir_Binky 1:9163a9f5fc36 372 long double temp,lat;
Sir_Binky 1:9163a9f5fc36 373 lat = TinyGPSLocation::lat();
Sir_Binky 1:9163a9f5fc36 374 if( lat >= 0 ) // North
Sir_Binky 1:9163a9f5fc36 375 {
Sir_Binky 1:9163a9f5fc36 376 temp = lat * 8388607; // 2^23 - 1
Sir_Binky 1:9163a9f5fc36 377 ret = temp / 90;
Sir_Binky 1:9163a9f5fc36 378 }
Sir_Binky 1:9163a9f5fc36 379 else // South
Sir_Binky 1:9163a9f5fc36 380 {
Sir_Binky 1:9163a9f5fc36 381 temp = lat * 8388608; // -2^23
Sir_Binky 1:9163a9f5fc36 382 ret = temp / 90;
Sir_Binky 1:9163a9f5fc36 383 }
Sir_Binky 1:9163a9f5fc36 384 return ret;
Sir_Binky 1:9163a9f5fc36 385 }
Sir_Binky 1:9163a9f5fc36 386
Sir_Binky 1:9163a9f5fc36 387 int32_t TinyGPSLocation::lngBinary()
Sir_Binky 1:9163a9f5fc36 388 {
Sir_Binky 1:9163a9f5fc36 389 int32_t ret;
Sir_Binky 1:9163a9f5fc36 390 long double temp,lng;
Sir_Binky 1:9163a9f5fc36 391 lng = TinyGPSLocation::lng();
Sir_Binky 1:9163a9f5fc36 392
Sir_Binky 1:9163a9f5fc36 393 if( lng >= 0 ) // East
Sir_Binky 1:9163a9f5fc36 394 {
Sir_Binky 1:9163a9f5fc36 395 temp = lng * 8388607; // 2^23 - 1
Sir_Binky 1:9163a9f5fc36 396 ret = temp / 180;
Sir_Binky 1:9163a9f5fc36 397 }
Sir_Binky 1:9163a9f5fc36 398 else // West
Sir_Binky 1:9163a9f5fc36 399 {
Sir_Binky 1:9163a9f5fc36 400 temp = lng * 8388608; // -2^23
Sir_Binky 1:9163a9f5fc36 401 ret = temp / 180;
Sir_Binky 1:9163a9f5fc36 402 }
Sir_Binky 1:9163a9f5fc36 403 return ret;
Sir_Binky 1:9163a9f5fc36 404 }
Sir_Binky 1:9163a9f5fc36 405
Sir_Binky 0:3407bd06cfae 406 void TinyGPSDate::commit()
Sir_Binky 0:3407bd06cfae 407 {
Sir_Binky 0:3407bd06cfae 408 date = newDate;
Sir_Binky 0:3407bd06cfae 409 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 410 valid = updated = true;
Sir_Binky 0:3407bd06cfae 411 }
Sir_Binky 0:3407bd06cfae 412
Sir_Binky 0:3407bd06cfae 413 void TinyGPSTime::commit()
Sir_Binky 0:3407bd06cfae 414 {
Sir_Binky 0:3407bd06cfae 415 time = newTime;
Sir_Binky 0:3407bd06cfae 416 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 417 valid = updated = true;
Sir_Binky 0:3407bd06cfae 418 }
Sir_Binky 0:3407bd06cfae 419
Sir_Binky 0:3407bd06cfae 420 void TinyGPSTime::setTime(const char *term)
Sir_Binky 0:3407bd06cfae 421 {
Sir_Binky 0:3407bd06cfae 422 newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
Sir_Binky 0:3407bd06cfae 423 }
Sir_Binky 0:3407bd06cfae 424
Sir_Binky 0:3407bd06cfae 425 void TinyGPSDate::setDate(const char *term)
Sir_Binky 0:3407bd06cfae 426 {
Sir_Binky 0:3407bd06cfae 427 newDate = atol(term);
Sir_Binky 0:3407bd06cfae 428 }
Sir_Binky 0:3407bd06cfae 429
Sir_Binky 0:3407bd06cfae 430 uint16_t TinyGPSDate::year()
Sir_Binky 0:3407bd06cfae 431 {
Sir_Binky 0:3407bd06cfae 432 updated = false;
Sir_Binky 0:3407bd06cfae 433 uint16_t year = date % 100;
Sir_Binky 0:3407bd06cfae 434 return year + 2000;
Sir_Binky 0:3407bd06cfae 435 }
Sir_Binky 0:3407bd06cfae 436
Sir_Binky 0:3407bd06cfae 437 uint8_t TinyGPSDate::month()
Sir_Binky 0:3407bd06cfae 438 {
Sir_Binky 0:3407bd06cfae 439 updated = false;
Sir_Binky 0:3407bd06cfae 440 return (date / 100) % 100;
Sir_Binky 0:3407bd06cfae 441 }
Sir_Binky 0:3407bd06cfae 442
Sir_Binky 0:3407bd06cfae 443 uint8_t TinyGPSDate::day()
Sir_Binky 0:3407bd06cfae 444 {
Sir_Binky 0:3407bd06cfae 445 updated = false;
Sir_Binky 0:3407bd06cfae 446 return date / 10000;
Sir_Binky 0:3407bd06cfae 447 }
Sir_Binky 0:3407bd06cfae 448
Sir_Binky 0:3407bd06cfae 449 uint8_t TinyGPSTime::hour()
Sir_Binky 0:3407bd06cfae 450 {
Sir_Binky 0:3407bd06cfae 451 updated = false;
Sir_Binky 0:3407bd06cfae 452 return time / 1000000;
Sir_Binky 0:3407bd06cfae 453 }
Sir_Binky 0:3407bd06cfae 454
Sir_Binky 0:3407bd06cfae 455 uint8_t TinyGPSTime::minute()
Sir_Binky 0:3407bd06cfae 456 {
Sir_Binky 0:3407bd06cfae 457 updated = false;
Sir_Binky 0:3407bd06cfae 458 return (time / 10000) % 100;
Sir_Binky 0:3407bd06cfae 459 }
Sir_Binky 0:3407bd06cfae 460
Sir_Binky 0:3407bd06cfae 461 uint8_t TinyGPSTime::second()
Sir_Binky 0:3407bd06cfae 462 {
Sir_Binky 0:3407bd06cfae 463 updated = false;
Sir_Binky 0:3407bd06cfae 464 return (time / 100) % 100;
Sir_Binky 0:3407bd06cfae 465 }
Sir_Binky 0:3407bd06cfae 466
Sir_Binky 0:3407bd06cfae 467 uint8_t TinyGPSTime::centisecond()
Sir_Binky 0:3407bd06cfae 468 {
Sir_Binky 0:3407bd06cfae 469 updated = false;
Sir_Binky 0:3407bd06cfae 470 return time % 100;
Sir_Binky 0:3407bd06cfae 471 }
Sir_Binky 0:3407bd06cfae 472
Sir_Binky 0:3407bd06cfae 473 void TinyGPSDecimal::commit()
Sir_Binky 0:3407bd06cfae 474 {
Sir_Binky 0:3407bd06cfae 475 val = newval;
Sir_Binky 0:3407bd06cfae 476 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 477 valid = updated = true;
Sir_Binky 0:3407bd06cfae 478 }
Sir_Binky 0:3407bd06cfae 479
Sir_Binky 0:3407bd06cfae 480 void TinyGPSDecimal::set(const char *term)
Sir_Binky 0:3407bd06cfae 481 {
Sir_Binky 0:3407bd06cfae 482 newval = TinyGPSPlus::parseDecimal(term);
Sir_Binky 0:3407bd06cfae 483 }
Sir_Binky 0:3407bd06cfae 484
Sir_Binky 0:3407bd06cfae 485 void TinyGPSInteger::commit()
Sir_Binky 0:3407bd06cfae 486 {
Sir_Binky 0:3407bd06cfae 487 val = newval;
Sir_Binky 0:3407bd06cfae 488 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 489 valid = updated = true;
Sir_Binky 0:3407bd06cfae 490 }
Sir_Binky 0:3407bd06cfae 491
Sir_Binky 0:3407bd06cfae 492 void TinyGPSInteger::set(const char *term)
Sir_Binky 0:3407bd06cfae 493 {
Sir_Binky 0:3407bd06cfae 494 newval = atol(term);
Sir_Binky 0:3407bd06cfae 495 }
Sir_Binky 0:3407bd06cfae 496
Sir_Binky 0:3407bd06cfae 497 TinyGPSCustom::TinyGPSCustom(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
Sir_Binky 0:3407bd06cfae 498 {
Sir_Binky 0:3407bd06cfae 499 begin(gps, _sentenceName, _termNumber);
Sir_Binky 0:3407bd06cfae 500 }
Sir_Binky 0:3407bd06cfae 501
Sir_Binky 0:3407bd06cfae 502 void TinyGPSCustom::begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
Sir_Binky 0:3407bd06cfae 503 {
Sir_Binky 0:3407bd06cfae 504 lastCommitTime = 0;
Sir_Binky 0:3407bd06cfae 505 updated = valid = false;
Sir_Binky 0:3407bd06cfae 506 sentenceName = _sentenceName;
Sir_Binky 0:3407bd06cfae 507 termNumber = _termNumber;
Sir_Binky 0:3407bd06cfae 508 memset(stagingBuffer, '\0', sizeof(stagingBuffer));
Sir_Binky 0:3407bd06cfae 509 memset(buffer, '\0', sizeof(buffer));
Sir_Binky 0:3407bd06cfae 510
Sir_Binky 0:3407bd06cfae 511 // Insert this item into the GPS tree
Sir_Binky 0:3407bd06cfae 512 gps.insertCustom(this, _sentenceName, _termNumber);
Sir_Binky 0:3407bd06cfae 513 }
Sir_Binky 0:3407bd06cfae 514
Sir_Binky 0:3407bd06cfae 515 void TinyGPSCustom::commit()
Sir_Binky 0:3407bd06cfae 516 {
Sir_Binky 0:3407bd06cfae 517 strcpy(this->buffer, this->stagingBuffer);
Sir_Binky 0:3407bd06cfae 518 lastCommitTime = millis();
Sir_Binky 0:3407bd06cfae 519 valid = updated = true;
Sir_Binky 0:3407bd06cfae 520 }
Sir_Binky 0:3407bd06cfae 521
Sir_Binky 0:3407bd06cfae 522 void TinyGPSCustom::set(const char *term)
Sir_Binky 0:3407bd06cfae 523 {
Sir_Binky 0:3407bd06cfae 524 strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer));
Sir_Binky 0:3407bd06cfae 525 }
Sir_Binky 0:3407bd06cfae 526
Sir_Binky 0:3407bd06cfae 527 void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
Sir_Binky 0:3407bd06cfae 528 {
Sir_Binky 0:3407bd06cfae 529 TinyGPSCustom **ppelt;
Sir_Binky 0:3407bd06cfae 530
Sir_Binky 0:3407bd06cfae 531 for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
Sir_Binky 0:3407bd06cfae 532 {
Sir_Binky 0:3407bd06cfae 533 int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
Sir_Binky 0:3407bd06cfae 534 if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
Sir_Binky 0:3407bd06cfae 535 break;
Sir_Binky 0:3407bd06cfae 536 }
Sir_Binky 0:3407bd06cfae 537
Sir_Binky 0:3407bd06cfae 538 pElt->next = *ppelt;
Sir_Binky 0:3407bd06cfae 539 *ppelt = pElt;
Sir_Binky 0:3407bd06cfae 540 }