diff --git a/minmea.c b/minmea.c index bd6fb06..8c5786c 100644 --- a/minmea.c +++ b/minmea.c @@ -271,6 +271,8 @@ enum minmea_type minmea_type(const char *sentence) return MINMEA_GPRMC; if (!strcmp(type, "GPGGA")) return MINMEA_GPGGA; + if (!strcmp(type, "GPGSA")) + return MINMEA_GPGSA; return MINMEA_UNKNOWN; } @@ -333,6 +335,65 @@ bool minmea_parse_gpgga(struct minmea_gpgga *frame, const char *sentence) return true; } +bool minmea_parse_gpgsa(struct minmea_gpgsa *frame, const char *sentence){ + // $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, + &frame->sat1, + &frame->sat2, + &frame->sat3, + &frame->sat4, + &frame->sat5, + &frame->sat6, + &frame->sat7, + &frame->sat8, + &frame->sat9, + &frame->sat10, + &frame->sat11, + &frame->sat12, + &frame->pdop, + &frame->pdop_scale, + &frame->hdop, + &frame->hdop_scale, + &frame->vdop, + &frame->vdop_scale + )){ + return false; + } + if (strcmp(type, "GPGSA")){ + return false; + } + + if(frame->mode == 'A'){ + frame->mode = GPGSA_MODE_AUTO; + } + else if(frame->mode == 'M'){ + frame->mode = GPGSA_MODE_FORCED; + } + else{ + return false; + } + + if(frame->fix_type == 1){ + frame->fix_type = GPGSA_FIX_NONE; + } + else if(frame->fix_type == 2){ + frame->fix_type = GPGSA_FIX_2D; + } + else if(frame->fix_type == 3){ + frame->fix_type = GPGSA_FIX_3D; + } + else{ + return false; + } + + return true; +} + int minmea_gettimeofday(struct timeval *tv, const struct minmea_date *date, const struct minmea_time *time) { if (date->year == -1 || time->hours == -1) diff --git a/minmea.h b/minmea.h index 94249ae..cd2e03e 100644 --- a/minmea.h +++ b/minmea.h @@ -27,6 +27,7 @@ enum minmea_type { MINMEA_UNKNOWN = 0, MINMEA_GPRMC, MINMEA_GPGGA, + MINMEA_GPGSA, }; struct minmea_date { @@ -65,6 +66,37 @@ struct minmea_gpgga { int dgps_age; }; +enum minmea_gpgsa_mode { + GPGSA_MODE_AUTO, + GPGSA_MODE_FORCED +}; + +enum minmea_gpgsa_fix_type { + GPGSA_FIX_NONE, + GPGSA_FIX_2D, + GPGSA_FIX_3D +}; + +struct minmea_gpgsa { + int mode; + int fix_type; + int sat1; + int sat2; + int sat3; + int sat4; + int sat5; + int sat6; + int sat7; + int sat8; + int sat9; + int sat10; + int sat11; + int sat12; + int pdop, pdop_scale; + int hdop, hdop_scale; + int vdop, vdop_scale; +}; + /** * Check sequence validity and checksum. Returns true for valid sequences. */ @@ -93,6 +125,7 @@ bool minmea_scan(const char *sentence, const char *format, ...); */ bool minmea_parse_gprmc(struct minmea_gprmc *frame, const char *sentence); bool minmea_parse_gpgga(struct minmea_gpgga *frame, const char *sentence); +bool minmea_parse_gpgsa(struct minmea_gpgsa *frame, const char *sentence); /** * Convert GPS UTC date/time representation to a UNIX timestamp. diff --git a/tests.c b/tests.c index 1744a3c..9c64c8d 100644 --- a/tests.c +++ b/tests.c @@ -328,11 +328,44 @@ START_TEST(test_minmea_parse_gpgga1) } END_TEST +START_TEST(test_minmea_parse_gpgsa1) +{ + const char *sentence = "$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39"; + struct minmea_gpgsa frame = {}; + struct minmea_gpgsa expected = { + .mode = GPGSA_MODE_AUTO, + .fix_type = GPGSA_FIX_3D, + .sat1 = 4, + .sat2 = 5, + .sat3 = 0, + .sat4 = 9, + .sat5 = 12, + .sat6 = 0, + .sat7 = 0, + .sat8 = 24, + .sat9 = 0, + .sat10 = 0, + .sat11 = 0, + .sat12 = 0, + .pdop = 25, + .pdop_scale = 10, + .hdop = 13, + .hdop_scale = 10, + .vdop = 21, + .vdop_scale = 10 + }; + ck_assert(minmea_check(sentence) == true); + ck_assert(minmea_parse_gpgsa(&frame, sentence) == true); + ck_assert(!memcmp(&frame, &expected, sizeof(frame))); +} +END_TEST + START_TEST(test_minmea_usage1) { const char *sentences[] = { "$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62", "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47", + "$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39", NULL, }; @@ -348,6 +381,12 @@ START_TEST(test_minmea_usage1) ck_assert(minmea_parse_gpgga(&frame, *sentence) == true); } break; + case MINMEA_GPGSA: { + struct minmea_gpgsa frame; + ck_assert(minmea_parse_gpgsa(&frame, *sentence) == true); + } break; + + default: { } break; } @@ -424,6 +463,7 @@ Suite *minmea_suite(void) tcase_add_test(tc_parse, test_minmea_parse_gprmc1); tcase_add_test(tc_parse, test_minmea_parse_gprmc2); tcase_add_test(tc_parse, test_minmea_parse_gpgga1); + tcase_add_test(tc_parse, test_minmea_parse_gpgsa1); suite_add_tcase(s, tc_parse); TCase *tc_usage = tcase_create("minmea_usage");