2014-02-17 03:03:14 +08:00
/*
* Copyright © 2014 Kosma Moczek < kosma @ cloudyourcar . com >
2014-02-26 23:27:24 +08:00
* This program is free software . It comes without any warranty , to the extent
* permitted by applicable law . You can redistribute it and / or modify it under
* the terms of the Do What The Fuck You Want To Public License , Version 2 , as
* published by Sam Hocevar . See the COPYING file for more details .
2014-02-17 03:03:14 +08:00
*/
2014-02-14 22:22:18 +08:00
# include "minmea.h"
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <stdarg.h>
2016-04-24 03:55:03 +08:00
# include <time.h>
2014-02-14 22:22:18 +08:00
# define boolstr(s) ((s) ? "true" : "false")
static int hex2int ( char c )
{
if ( c > = ' 0 ' & & c < = ' 9 ' )
return c - ' 0 ' ;
if ( c > = ' A ' & & c < = ' F ' )
2014-02-26 20:19:00 +08:00
return c - ' A ' + 10 ;
2014-02-14 22:22:18 +08:00
if ( c > = ' a ' & & c < = ' f ' )
2014-02-26 20:19:00 +08:00
return c - ' a ' + 10 ;
2014-02-14 22:22:18 +08:00
return - 1 ;
}
2014-09-12 00:02:29 +08:00
uint8_t minmea_checksum ( const char * sentence )
{
// Support senteces with or without the starting dollar sign.
if ( * sentence = = ' $ ' )
sentence + + ;
uint8_t checksum = 0x00 ;
// The optional checksum is an XOR of all bytes between "$" and "*".
while ( * sentence & & * sentence ! = ' * ' )
checksum ^ = * sentence + + ;
return checksum ;
}
2014-09-11 21:19:11 +08:00
bool minmea_check ( const char * sentence , bool strict )
2014-02-14 22:22:18 +08:00
{
uint8_t checksum = 0x00 ;
// Sequence length is limited.
if ( strlen ( sentence ) > MINMEA_MAX_LENGTH + 3 )
return false ;
// A valid sentence starts with "$".
if ( * sentence + + ! = ' $ ' )
return false ;
// The optional checksum is an XOR of all bytes between "$" and "*".
2014-02-15 00:17:59 +08:00
while ( * sentence & & * sentence ! = ' * ' & & isprint ( ( unsigned char ) * sentence ) )
2014-02-14 22:22:18 +08:00
checksum ^ = * sentence + + ;
2014-09-11 21:19:11 +08:00
// If checksum is present...
2014-02-14 22:22:18 +08:00
if ( * sentence = = ' * ' ) {
// Extract checksum.
sentence + + ;
int upper = hex2int ( * sentence + + ) ;
if ( upper = = - 1 )
return false ;
int lower = hex2int ( * sentence + + ) ;
if ( lower = = - 1 )
return false ;
int expected = upper < < 4 | lower ;
// Check for checksum mismatch.
if ( checksum ! = expected )
return false ;
2014-09-11 21:19:11 +08:00
} else if ( strict ) {
// Discard non-checksummed frames in strict mode.
return false ;
2014-02-14 22:22:18 +08:00
}
// The only stuff allowed at this point is a newline.
if ( * sentence & & strcmp ( sentence , " \n " ) & & strcmp ( sentence , " \r \n " ) )
return false ;
return true ;
}
static inline bool minmea_isfield ( char c ) {
2014-02-15 00:17:59 +08:00
return isprint ( ( unsigned char ) c ) & & c ! = ' , ' & & c ! = ' * ' ;
2014-02-14 22:22:18 +08:00
}
bool minmea_scan ( const char * sentence , const char * format , . . . )
{
bool result = false ;
2014-04-24 00:15:26 +08:00
bool optional = false ;
2014-02-14 22:22:18 +08:00
va_list ap ;
va_start ( ap , format ) ;
const char * field = sentence ;
# define next_field() \
do { \
2014-04-24 00:15:26 +08:00
/* Progress to the next field. */ \
while ( minmea_isfield ( * sentence ) ) \
sentence + + ; \
/* Make sure there is a field there. */ \
if ( * sentence = = ' , ' ) { \
sentence + + ; \
field = sentence ; \
} else { \
field = NULL ; \
} \
2014-02-14 22:22:18 +08:00
} while ( 0 )
while ( * format ) {
char type = * format + + ;
2014-04-24 00:15:26 +08:00
if ( type = = ' ; ' ) {
// All further fields are optional.
optional = true ;
continue ;
}
if ( ! field & & ! optional ) {
// Field requested but we ran out if input. Bail out.
goto parse_error ;
}
2014-02-14 22:22:18 +08:00
switch ( type ) {
case ' c ' : { // Single character field (char).
char value = ' \0 ' ;
2014-04-24 00:15:26 +08:00
if ( field & & minmea_isfield ( * field ) )
2014-02-14 22:22:18 +08:00
value = * field ;
* va_arg ( ap , char * ) = value ;
} break ;
case ' d ' : { // Single character direction field (int).
int value = 0 ;
2014-04-24 00:15:26 +08:00
if ( field & & minmea_isfield ( * field ) ) {
2014-02-14 22:22:18 +08:00
switch ( * field ) {
case ' N ' :
case ' E ' :
value = 1 ;
break ;
case ' S ' :
case ' W ' :
value = - 1 ;
break ;
default :
2014-04-24 00:15:26 +08:00
goto parse_error ;
2014-02-14 22:22:18 +08:00
}
}
* va_arg ( ap , int * ) = value ;
} break ;
2014-04-27 22:22:37 +08:00
case ' f ' : { // Fractional value with scale (struct minmea_float).
2014-02-14 22:22:18 +08:00
int sign = 0 ;
2014-04-27 22:22:37 +08:00
int_least32_t value = - 1 ;
int_least32_t scale = 0 ;
2014-02-14 22:22:18 +08:00
2014-04-24 00:15:26 +08:00
if ( field ) {
while ( minmea_isfield ( * field ) ) {
if ( * field = = ' + ' & & ! sign & & value = = - 1 ) {
sign = 1 ;
} else if ( * field = = ' - ' & & ! sign & & value = = - 1 ) {
sign = - 1 ;
} else if ( isdigit ( ( unsigned char ) * field ) ) {
2014-04-27 23:19:29 +08:00
int digit = * field - ' 0 ' ;
2014-04-24 00:15:26 +08:00
if ( value = = - 1 )
value = 0 ;
2014-04-27 23:19:29 +08:00
if ( value > ( INT_LEAST32_MAX - digit ) / 10 ) {
/* we ran out of bits, what do we do? */
if ( scale ) {
/* truncate extra precision */
break ;
} else {
/* integer overflow. bail out. */
goto parse_error ;
}
}
value = ( 10 * value ) + digit ;
2014-04-24 00:15:26 +08:00
if ( scale )
scale * = 10 ;
} else if ( * field = = ' . ' & & scale = = 0 ) {
scale = 1 ;
2014-07-30 21:18:22 +08:00
} else if ( * field = = ' ' ) {
/* Allow spaces at the start of the field. Not NMEA
* conformant , but some modules do this . */
if ( sign ! = 0 | | value ! = - 1 | | scale ! = 0 )
goto parse_error ;
2014-04-24 00:15:26 +08:00
} else {
goto parse_error ;
}
field + + ;
2014-02-14 22:22:18 +08:00
}
}
if ( ( sign | | scale ) & & value = = - 1 )
2014-04-24 00:15:26 +08:00
goto parse_error ;
2014-02-14 22:22:18 +08:00
if ( value = = - 1 ) {
2014-04-27 23:06:10 +08:00
/* No digits were scanned. */
2014-02-14 22:22:18 +08:00
value = 0 ;
scale = 0 ;
2014-04-27 23:06:10 +08:00
} else if ( scale = = 0 ) {
/* No decimal point. */
scale = 1 ;
2014-02-14 22:22:18 +08:00
}
if ( sign )
value * = sign ;
2014-04-27 22:22:37 +08:00
* va_arg ( ap , struct minmea_float * ) = ( struct minmea_float ) { value , scale } ;
2014-02-14 22:22:18 +08:00
} break ;
case ' i ' : { // Integer value, default 0 (int).
2014-04-24 00:15:26 +08:00
int value = 0 ;
2014-02-14 22:22:18 +08:00
2014-04-24 00:15:26 +08:00
if ( field ) {
char * endptr ;
value = strtol ( field , & endptr , 10 ) ;
if ( minmea_isfield ( * endptr ) )
goto parse_error ;
}
2014-02-14 22:22:18 +08:00
* va_arg ( ap , int * ) = value ;
} break ;
case ' s ' : { // String value (char *).
char * buf = va_arg ( ap , char * ) ;
2014-04-24 00:15:26 +08:00
if ( field ) {
while ( minmea_isfield ( * field ) )
* buf + + = * field + + ;
}
2014-02-14 22:22:18 +08:00
* buf = ' \0 ' ;
} break ;
2014-03-25 05:40:25 +08:00
case ' t ' : { // NMEA talker+sentence identifier (char *).
2014-04-24 00:15:26 +08:00
// This field is always mandatory.
if ( ! field )
goto parse_error ;
2014-02-14 22:22:18 +08:00
if ( field [ 0 ] ! = ' $ ' )
2014-04-24 00:15:26 +08:00
goto parse_error ;
2014-05-28 21:38:23 +08:00
for ( int f = 0 ; f < 5 ; f + + )
2014-05-28 21:41:42 +08:00
if ( ! minmea_isfield ( field [ 1 + f ] ) )
2014-04-24 00:15:26 +08:00
goto parse_error ;
2014-02-14 22:22:18 +08:00
char * buf = va_arg ( ap , char * ) ;
memcpy ( buf , field + 1 , 5 ) ;
buf [ 5 ] = ' \0 ' ;
} break ;
case ' D ' : { // Date (int, int, int), -1 if empty.
struct minmea_date * date = va_arg ( ap , struct minmea_date * ) ;
int d = - 1 , m = - 1 , y = - 1 ;
2014-04-24 00:15:26 +08:00
if ( field & & minmea_isfield ( * field ) ) {
// Always six digits.
2014-05-28 21:38:23 +08:00
for ( int f = 0 ; f < 6 ; f + + )
if ( ! isdigit ( ( unsigned char ) field [ f ] ) )
2014-04-24 00:15:26 +08:00
goto parse_error ;
2016-03-03 01:44:44 +08:00
char dArr [ ] = { field [ 0 ] , field [ 1 ] , ' \0 ' } ;
char mArr [ ] = { field [ 2 ] , field [ 3 ] , ' \0 ' } ;
char yArr [ ] = { field [ 4 ] , field [ 5 ] , ' \0 ' } ;
2016-03-02 16:38:37 +08:00
d = strtol ( dArr , NULL , 10 ) ;
m = strtol ( mArr , NULL , 10 ) ;
y = strtol ( yArr , NULL , 10 ) ;
2014-04-24 00:15:26 +08:00
}
2014-02-14 22:22:18 +08:00
date - > day = d ;
date - > month = m ;
date - > year = y ;
} break ;
case ' T ' : { // Time (int, int, int, int), -1 if empty.
2014-06-17 08:49:47 +08:00
struct minmea_time * time_ = va_arg ( ap , struct minmea_time * ) ;
2014-02-14 22:22:18 +08:00
int h = - 1 , i = - 1 , s = - 1 , u = - 1 ;
2014-04-24 00:15:26 +08:00
if ( field & & minmea_isfield ( * field ) ) {
// Minimum required: integer time.
2014-05-28 21:38:23 +08:00
for ( int f = 0 ; f < 6 ; f + + )
if ( ! isdigit ( ( unsigned char ) field [ f ] ) )
2014-04-24 00:15:26 +08:00
goto parse_error ;
2016-03-03 01:44:44 +08:00
char hArr [ ] = { field [ 0 ] , field [ 1 ] , ' \0 ' } ;
char iArr [ ] = { field [ 2 ] , field [ 3 ] , ' \0 ' } ;
char sArr [ ] = { field [ 4 ] , field [ 5 ] , ' \0 ' } ;
2016-03-02 16:38:37 +08:00
h = strtol ( hArr , NULL , 10 ) ;
i = strtol ( iArr , NULL , 10 ) ;
s = strtol ( sArr , NULL , 10 ) ;
2014-04-24 00:15:26 +08:00
field + = 6 ;
// Extra: fractional time. Saved as microseconds.
if ( * field + + = = ' . ' ) {
2017-05-20 21:08:16 +08:00
uint32_t value = 0 ;
uint32_t scale = 1000000LU ;
2014-04-24 00:15:26 +08:00
while ( isdigit ( ( unsigned char ) * field ) & & scale > 1 ) {
value = ( value * 10 ) + ( * field + + - ' 0 ' ) ;
scale / = 10 ;
}
u = value * scale ;
} else {
u = 0 ;
2014-02-14 22:22:18 +08:00
}
}
2014-06-17 08:49:47 +08:00
time_ - > hours = h ;
time_ - > minutes = i ;
time_ - > seconds = s ;
time_ - > microseconds = u ;
2014-02-14 22:22:18 +08:00
} break ;
case ' _ ' : { // Ignore the field.
} break ;
default : { // Unknown.
2014-04-24 00:15:26 +08:00
goto parse_error ;
2014-02-14 22:22:18 +08:00
} break ;
}
next_field ( ) ;
}
result = true ;
2014-04-24 00:15:26 +08:00
parse_error :
2014-02-14 22:22:18 +08:00
va_end ( ap ) ;
return result ;
}
2014-03-25 06:13:05 +08:00
bool minmea_talker_id ( char talker [ 3 ] , const char * sentence )
{
char type [ 6 ] ;
if ( ! minmea_scan ( sentence , " t " , type ) )
return false ;
talker [ 0 ] = type [ 0 ] ;
talker [ 1 ] = type [ 1 ] ;
talker [ 2 ] = ' \0 ' ;
return true ;
}
2014-09-11 21:19:11 +08:00
enum minmea_sentence_id minmea_sentence_id ( const char * sentence , bool strict )
2014-02-14 22:22:18 +08:00
{
2014-09-11 21:19:11 +08:00
if ( ! minmea_check ( sentence , strict ) )
2014-02-14 22:22:18 +08:00
return MINMEA_INVALID ;
char type [ 6 ] ;
if ( ! minmea_scan ( sentence , " t " , type ) )
return MINMEA_INVALID ;
2014-03-25 05:40:25 +08:00
if ( ! strcmp ( type + 2 , " RMC " ) )
return MINMEA_SENTENCE_RMC ;
if ( ! strcmp ( type + 2 , " GGA " ) )
return MINMEA_SENTENCE_GGA ;
if ( ! strcmp ( type + 2 , " GSA " ) )
return MINMEA_SENTENCE_GSA ;
2014-04-15 21:55:14 +08:00
if ( ! strcmp ( type + 2 , " GLL " ) )
return MINMEA_SENTENCE_GLL ;
2014-04-24 01:57:30 +08:00
if ( ! strcmp ( type + 2 , " GST " ) )
2014-04-21 01:21:05 +08:00
return MINMEA_SENTENCE_GST ;
2014-04-24 05:43:28 +08:00
if ( ! strcmp ( type + 2 , " GSV " ) )
return MINMEA_SENTENCE_GSV ;
2016-04-24 03:19:26 +08:00
if ( ! strcmp ( type + 2 , " VTG " ) )
return MINMEA_SENTENCE_VTG ;
2017-06-16 18:54:17 +08:00
if ( ! strcmp ( type + 2 , " ZDA " ) )
return MINMEA_SENTENCE_ZDA ;
2014-02-14 22:22:18 +08:00
return MINMEA_UNKNOWN ;
}
2014-03-25 05:40:25 +08:00
bool minmea_parse_rmc ( struct minmea_sentence_rmc * frame , const char * sentence )
2014-02-14 22:22:18 +08:00
{
// $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
char type [ 6 ] ;
char validity ;
int latitude_direction ;
int longitude_direction ;
int variation_direction ;
if ( ! minmea_scan ( sentence , " tTcfdfdffDfd " ,
type ,
& frame - > time ,
& validity ,
2014-04-27 22:22:37 +08:00
& frame - > latitude , & latitude_direction ,
& frame - > longitude , & longitude_direction ,
& frame - > speed ,
& frame - > course ,
2014-02-14 22:22:18 +08:00
& frame - > date ,
2014-04-27 22:22:37 +08:00
& frame - > variation , & variation_direction ) )
2014-02-14 22:22:18 +08:00
return false ;
2014-03-25 05:40:25 +08:00
if ( strcmp ( type + 2 , " RMC " ) )
2014-02-14 22:22:18 +08:00
return false ;
frame - > valid = ( validity = = ' A ' ) ;
2014-04-27 22:22:37 +08:00
frame - > latitude . value * = latitude_direction ;
frame - > longitude . value * = longitude_direction ;
frame - > variation . value * = variation_direction ;
2014-02-14 22:22:18 +08:00
return true ;
}
2014-03-25 05:40:25 +08:00
bool minmea_parse_gga ( struct minmea_sentence_gga * frame , const char * sentence )
2014-02-14 22:22:18 +08:00
{
// $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
char type [ 6 ] ;
int latitude_direction ;
int longitude_direction ;
if ( ! minmea_scan ( sentence , " tTfdfdiiffcfci_ " ,
type ,
& frame - > time ,
2014-04-27 22:22:37 +08:00
& frame - > latitude , & latitude_direction ,
& frame - > longitude , & longitude_direction ,
2014-02-14 22:22:18 +08:00
& frame - > fix_quality ,
& frame - > satellites_tracked ,
2014-04-27 22:22:37 +08:00
& frame - > hdop ,
& frame - > altitude , & frame - > altitude_units ,
& frame - > height , & frame - > height_units ,
2014-02-14 22:22:18 +08:00
& frame - > dgps_age ) )
return false ;
2014-03-25 05:40:25 +08:00
if ( strcmp ( type + 2 , " GGA " ) )
2014-02-14 22:22:18 +08:00
return false ;
2014-04-27 22:22:37 +08:00
frame - > latitude . value * = latitude_direction ;
frame - > longitude . value * = longitude_direction ;
2014-02-14 22:22:18 +08:00
return true ;
}
2014-03-25 05:40:25 +08:00
bool minmea_parse_gsa ( struct minmea_sentence_gsa * frame , const char * sentence )
2014-02-26 22:03:20 +08:00
{
// $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
char type [ 6 ] ;
if ( ! minmea_scan ( sentence , " tciiiiiiiiiiiiifff " ,
type ,
& frame - > mode ,
& frame - > fix_type ,
2014-02-26 22:07:42 +08:00
& frame - > sats [ 0 ] ,
& frame - > sats [ 1 ] ,
& frame - > sats [ 2 ] ,
& frame - > sats [ 3 ] ,
& frame - > sats [ 4 ] ,
& frame - > sats [ 5 ] ,
& frame - > sats [ 6 ] ,
& frame - > sats [ 7 ] ,
& frame - > sats [ 8 ] ,
& frame - > sats [ 9 ] ,
& frame - > sats [ 10 ] ,
& frame - > sats [ 11 ] ,
2014-02-26 22:03:20 +08:00
& frame - > pdop ,
& frame - > hdop ,
2014-04-27 22:22:37 +08:00
& frame - > vdop ) )
2014-02-26 22:03:20 +08:00
return false ;
2014-03-25 05:40:25 +08:00
if ( strcmp ( type + 2 , " GSA " ) )
2014-02-26 22:03:20 +08:00
return false ;
return true ;
2014-02-26 00:32:56 +08:00
}
2014-04-15 21:55:14 +08:00
bool minmea_parse_gll ( struct minmea_sentence_gll * frame , const char * sentence )
{
// $GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41$;
char type [ 6 ] ;
int latitude_direction ;
int longitude_direction ;
2014-06-17 21:00:51 +08:00
if ( ! minmea_scan ( sentence , " tfdfdTc;c " ,
2014-04-15 21:55:14 +08:00
type ,
2014-06-17 20:57:08 +08:00
& frame - > latitude , & latitude_direction ,
& frame - > longitude , & longitude_direction ,
2014-04-15 21:55:14 +08:00
& frame - > time ,
& frame - > status ,
& frame - > mode ) )
return false ;
if ( strcmp ( type + 2 , " GLL " ) )
return false ;
2014-06-17 20:57:08 +08:00
frame - > latitude . value * = latitude_direction ;
frame - > longitude . value * = longitude_direction ;
2014-04-15 21:55:14 +08:00
return true ;
}
2014-04-20 16:27:22 +08:00
bool minmea_parse_gst ( struct minmea_sentence_gst * frame , const char * sentence )
{
// $GPGST,024603.00,3.2,6.6,4.7,47.3,5.8,5.6,22.0*58
char type [ 6 ] ;
if ( ! minmea_scan ( sentence , " tTfffffff " ,
type ,
& frame - > time ,
2014-04-27 22:22:37 +08:00
& frame - > rms_deviation ,
& frame - > semi_major_deviation ,
& frame - > semi_minor_deviation ,
& frame - > semi_major_orientation ,
& frame - > latitude_error_deviation ,
& frame - > longitude_error_deviation ,
& frame - > altitude_error_deviation ) )
2014-04-20 16:27:22 +08:00
return false ;
if ( strcmp ( type + 2 , " GST " ) )
return false ;
return true ;
}
2014-04-24 05:43:28 +08:00
bool minmea_parse_gsv ( struct minmea_sentence_gsv * frame , const char * sentence )
{
// $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
2014-06-17 08:50:27 +08:00
// $GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D
// $GPGSV,4,2,11,08,51,203,30,09,45,215,28*75
// $GPGSV,4,4,13,39,31,170,27*40
// $GPGSV,4,4,13*7B
2014-04-24 05:43:28 +08:00
char type [ 6 ] ;
2014-06-17 08:50:27 +08:00
if ( ! minmea_scan ( sentence , " tiii;iiiiiiiiiiiiiiii " ,
2014-04-24 05:43:28 +08:00
type ,
& frame - > total_msgs ,
& frame - > msg_nr ,
& frame - > total_sats ,
& frame - > sats [ 0 ] . nr ,
& frame - > sats [ 0 ] . elevation ,
& frame - > sats [ 0 ] . azimuth ,
& frame - > sats [ 0 ] . snr ,
& frame - > sats [ 1 ] . nr ,
& frame - > sats [ 1 ] . elevation ,
& frame - > sats [ 1 ] . azimuth ,
& frame - > sats [ 1 ] . snr ,
& frame - > sats [ 2 ] . nr ,
& frame - > sats [ 2 ] . elevation ,
& frame - > sats [ 2 ] . azimuth ,
& frame - > sats [ 2 ] . snr ,
& frame - > sats [ 3 ] . nr ,
& frame - > sats [ 3 ] . elevation ,
& frame - > sats [ 3 ] . azimuth ,
& frame - > sats [ 3 ] . snr
) ) {
return false ;
}
if ( strcmp ( type + 2 , " GSV " ) )
return false ;
return true ;
}
2014-04-20 16:27:22 +08:00
2016-04-24 03:19:26 +08:00
bool minmea_parse_vtg ( struct minmea_sentence_vtg * frame , const char * sentence )
{
// $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48
// $GPVTG,156.1,T,140.9,M,0.0,N,0.0,K*41
// $GPVTG,096.5,T,083.5,M,0.0,N,0.0,K,D*22
// $GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F
char type [ 6 ] ;
char c_true , c_magnetic , c_knots , c_kph , c_faa_mode ;
if ( ! minmea_scan ( sentence , " tfcfcfcfc;c " ,
type ,
& frame - > true_track_degrees ,
& c_true ,
& frame - > magnetic_track_degrees ,
& c_magnetic ,
& frame - > speed_knots ,
& c_knots ,
& frame - > speed_kph ,
& c_kph ,
& c_faa_mode ) )
return false ;
if ( strcmp ( type + 2 , " VTG " ) )
return false ;
// check chars
if ( c_true ! = ' T ' | |
c_magnetic ! = ' M ' | |
c_knots ! = ' N ' | |
c_kph ! = ' K ' )
return false ;
frame - > faa_mode = c_faa_mode ;
return true ;
}
2017-06-16 18:54:17 +08:00
bool minmea_parse_zda ( struct minmea_sentence_zda * frame , const char * sentence )
{
// $GPZDA,201530.00,04,07,2002,00,00*60
char type [ 6 ] ;
if ( ! minmea_scan ( sentence , " tTiiiii " ,
type ,
& frame - > time ,
& frame - > date . day ,
& frame - > date . month ,
& frame - > date . year ,
& frame - > hour_offset ,
& frame - > minute_offset ) )
return false ;
if ( strcmp ( type + 2 , " ZDA " ) )
return false ;
// check offsets
if ( abs ( frame - > hour_offset ) > 13 | |
frame - > minute_offset > 59 | |
frame - > minute_offset < 0 )
return false ;
return true ;
}
2014-07-11 18:18:47 +08:00
int minmea_gettime ( struct timespec * ts , const struct minmea_date * date , const struct minmea_time * time_ )
2014-02-14 22:22:18 +08:00
{
2014-06-17 08:49:47 +08:00
if ( date - > year = = - 1 | | time_ - > hours = = - 1 )
2014-02-14 22:22:18 +08:00
return - 1 ;
struct tm tm ;
2014-05-28 22:06:32 +08:00
memset ( & tm , 0 , sizeof ( tm ) ) ;
2017-09-26 02:34:35 +08:00
tm . tm_year = date - > year % 100 ; // ZDA parser stores 4 digit year, filter centuries here so raw information is preserved in struct minmea_sentence_zda if user needs it.
2017-09-26 00:23:26 +08:00
if ( tm . tm_year < 80 ) // GPS epoch begins 1980, assume a year range of 1980 to 2079 for the library.
{
2017-09-26 02:34:35 +08:00
tm . tm_year = 2000 + tm . tm_year - 1900 ;
2017-09-26 00:23:26 +08:00
}
2014-02-14 22:22:18 +08:00
tm . tm_mon = date - > month - 1 ;
tm . tm_mday = date - > day ;
2014-06-17 08:49:47 +08:00
tm . tm_hour = time_ - > hours ;
tm . tm_min = time_ - > minutes ;
tm . tm_sec = time_ - > seconds ;
2014-02-14 22:22:18 +08:00
2014-06-18 18:13:14 +08:00
time_t timestamp = timegm ( & tm ) ; /* See README.md if your system lacks timegm(). */
2014-02-14 22:22:18 +08:00
if ( timestamp ! = - 1 ) {
2014-07-11 18:18:47 +08:00
ts - > tv_sec = timestamp ;
ts - > tv_nsec = time_ - > microseconds * 1000 ;
2014-02-14 22:22:18 +08:00
return 0 ;
} else {
return - 1 ;
}
}
/* vim: set ts=4 sw=4 et: */