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/
TinyGPSplus.cpp@1:9163a9f5fc36, 2016-01-22 (annotated)
- 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?
User | Revision | Line number | New 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 °) |
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 | } |