33#if !defined(ARDUINO) && !defined(__AVR__)
37 static auto start_time = std::chrono::high_resolution_clock::now();
39 auto end_time = std::chrono::high_resolution_clock::now();
40 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
42 return static_cast<unsigned long>(duration.count());
48 , isChecksumTerm(false)
49 , curSentenceType(GPS_SENTENCE_OTHER)
52 , sentenceHasFix(false)
56 , sentencesWithFixCount(0)
57 , failedChecksumCount(0)
58 , passedChecksumCount(0)
79 bool isValidSentence =
false;
80 if (curTermOffset <
sizeof(term))
82 term[curTermOffset] = 0;
83 isValidSentence = endOfTermHandler();
87 isChecksumTerm = c ==
'*';
88 return isValidSentence;
93 curTermNumber = curTermOffset = 0;
95 curSentenceType = GPS_SENTENCE_OTHER;
96 isChecksumTerm =
false;
97 sentenceHasFix =
false;
101 if (curTermOffset <
sizeof(term) - 1)
102 term[curTermOffset++] = c;
114int TinyGPSPlus::fromHex(
char a)
116 if (a >=
'A' && a <=
'F')
118 else if (a >=
'a' && a <=
'f')
128 bool negative = *term ==
'-';
129 if (negative) ++term;
130 int32_t ret = 100 * (int32_t)atol(term);
131 while (isdigit(*term)) ++term;
132 if (*term ==
'.' && isdigit(term[1]))
134 ret += 10 * (term[1] -
'0');
135 if (isdigit(term[2]))
136 ret += term[2] -
'0';
138 return negative ? -ret : ret;
145 uint32_t leftOfDecimal = (uint32_t)atol(term);
146 uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
147 uint32_t multiplier = 10000000UL;
148 uint32_t tenMillionthsOfMinutes = minutes * multiplier;
150 deg.
deg = (int16_t)(leftOfDecimal / 100);
152 while (isdigit(*term))
156 while (isdigit(*++term))
159 tenMillionthsOfMinutes += (*term -
'0') * multiplier;
162 deg.
billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
166#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
170bool TinyGPSPlus::endOfTermHandler()
175 byte checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
176 if (checksum == parity)
178 passedChecksumCount++;
180 ++sentencesWithFixCount;
182 switch(curSentenceType)
184 case GPS_SENTENCE_RMC:
194 case GPS_SENTENCE_GGA:
207 for (
TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
214 ++failedChecksumCount;
221 if (curTermNumber == 0)
223 if (strchr(
"GB", term[0]) && strchr(
"PNABLD", term[1]) != NULL && !strcmp(term + 2,
_RMCterm))
224 curSentenceType = GPS_SENTENCE_RMC;
225 else if (strchr(
"GB", term[0]) && strchr(
"PNABLD", term[1]) != NULL && !strcmp(term + 2,
_GGAterm))
226 curSentenceType = GPS_SENTENCE_GGA;
228 curSentenceType = GPS_SENTENCE_OTHER;
231 for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
232 if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
233 customCandidates = NULL;
238 if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
239 switch(
COMBINE(curSentenceType, curTermNumber))
241 case COMBINE(GPS_SENTENCE_RMC, 1):
242 case COMBINE(GPS_SENTENCE_GGA, 1):
245 case COMBINE(GPS_SENTENCE_RMC, 2):
246 sentenceHasFix = term[0] ==
'A';
248 case COMBINE(GPS_SENTENCE_RMC, 3):
249 case COMBINE(GPS_SENTENCE_GGA, 2):
252 case COMBINE(GPS_SENTENCE_RMC, 4):
253 case COMBINE(GPS_SENTENCE_GGA, 3):
256 case COMBINE(GPS_SENTENCE_RMC, 5):
257 case COMBINE(GPS_SENTENCE_GGA, 4):
260 case COMBINE(GPS_SENTENCE_RMC, 6):
261 case COMBINE(GPS_SENTENCE_GGA, 5):
264 case COMBINE(GPS_SENTENCE_RMC, 7):
267 case COMBINE(GPS_SENTENCE_RMC, 8):
270 case COMBINE(GPS_SENTENCE_RMC, 9):
273 case COMBINE(GPS_SENTENCE_GGA, 6):
274 sentenceHasFix = term[0] >
'0';
277 case COMBINE(GPS_SENTENCE_GGA, 7):
280 case COMBINE(GPS_SENTENCE_GGA, 8):
283 case COMBINE(GPS_SENTENCE_GGA, 9):
286 case COMBINE(GPS_SENTENCE_RMC, 12):
292 for (
TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
293 if (p->termNumber == curTermNumber)
307 double delta = radians(long1-long2);
308 double sdlong = sin(delta);
309 double cdlong = cos(delta);
310 lat1 = radians(lat1);
311 lat2 = radians(lat2);
312 double slat1 = sin(lat1);
313 double clat1 = cos(lat1);
314 double slat2 = sin(lat2);
315 double clat2 = cos(lat2);
316 delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
318 delta += sq(clat2 * sdlong);
320 double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
321 delta = atan2(delta, denom);
331 double dlon = radians(long2-long1);
332 lat1 = radians(lat1);
333 lat2 = radians(lat2);
334 double a1 = sin(dlon) * cos(lat2);
335 double a2 = sin(lat1) * cos(lat2) * cos(dlon);
336 a2 = cos(lat1) * sin(lat2) - a2;
347 static const char* directions[] = {
"N",
"NNE",
"NE",
"ENE",
"E",
"ESE",
"SE",
"SSE",
"S",
"SSW",
"SW",
"WSW",
"W",
"WNW",
"NW",
"NNW"};
348 int direction = (int)((
course + 11.25f) / 22.5f);
349 return directions[direction % 16];
352void TinyGPSLocation::commit()
354 rawLatData = rawNewLatData;
355 rawLngData = rawNewLngData;
356 fixQuality = newFixQuality;
357 fixMode = newFixMode;
358 lastCommitTime =
millis();
359 valid = updated =
true;
362void TinyGPSLocation::setLatitude(
const char *term)
367void TinyGPSLocation::setLongitude(
const char *term)
375 double ret = rawLatData.
deg + rawLatData.
billionths / 1000000000.0;
376 return rawLatData.
negative ? -ret : ret;
382 double ret = rawLngData.
deg + rawLngData.
billionths / 1000000000.0;
383 return rawLngData.
negative ? -ret : ret;
386void TinyGPSDate::commit()
389 lastCommitTime =
millis();
390 valid = updated =
true;
393void TinyGPSTime::commit()
396 lastCommitTime =
millis();
397 valid = updated =
true;
400void TinyGPSTime::setTime(
const char *term)
405void TinyGPSDate::setDate(
const char *term)
407 newDate = atol(term);
413 uint16_t
year = date % 100;
420 return (date / 100) % 100;
432 return time / 1000000;
438 return (time / 10000) % 100;
444 return (time / 100) % 100;
453void TinyGPSDecimal::commit()
456 lastCommitTime =
millis();
457 valid = updated =
true;
460void TinyGPSDecimal::set(
const char *term)
465void TinyGPSInteger::commit()
468 lastCommitTime =
millis();
469 valid = updated =
true;
472void TinyGPSInteger::set(
const char *term)
479 begin(
gps, _sentenceName, _termNumber);
485 updated = valid =
false;
486 sentenceName = _sentenceName;
487 termNumber = _termNumber;
488 memset(stagingBuffer,
'\0',
sizeof(stagingBuffer));
489 memset(buffer,
'\0',
sizeof(buffer));
492 gps.insertCustom(
this, _sentenceName, _termNumber);
495void TinyGPSCustom::commit()
497 strcpy(this->buffer, this->stagingBuffer);
498 lastCommitTime =
millis();
499 valid = updated =
true;
502void TinyGPSCustom::set(
const char *term)
504 strncpy(this->stagingBuffer, term,
sizeof(this->stagingBuffer) - 1);
507void TinyGPSPlus::insertCustom(
TinyGPSCustom *pElt,
const char *sentenceName,
int termNumber)
511 for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
513 int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
514 if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
MultipleSatellite gps(Serial1, GPSBaud, SERIAL_8N1, TinyGPS_RXPin, TinyGPS_TXPin)
#define COMBINE(sentence_type, term_number)
#define _GPS_EARTH_MEAN_RADIUS
void begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
static void parseDegrees(const char *term, RawDegrees °)
static int32_t parseDecimal(const char *term)
TinyGPSInteger satellites
static const char * cardinal(double course)
static double distanceBetween(double lat1, double long1, double lat2, double long2)
static double courseTo(double lat1, double long1, double lat2, double long2)