From 95f6beec4fd167f1524a6052ea9b4c3a9fc6551d Mon Sep 17 00:00:00 2001 From: lvitya Date: Sat, 23 Apr 2016 22:19:26 +0300 Subject: [PATCH] Add $--VTG sentences. * Fix padding problem in test_minmea_parse_gll1 * Add support for $--VTG sentences. * Add tests for $--VTG sentences. * Fix padding problem in test_minmea_parse_gll1. 2nd attempt. --- README.md | 3 ++- example.c | 17 +++++++++++++ minmea.c | 36 +++++++++++++++++++++++++++ minmea.h | 23 +++++++++++++++--- tests.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 139 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 299ce3c..f229a45 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,9 @@ systems. * ``GLL`` (Geographic Position: Latitude/Longitude) * ``GST`` (Pseudorange Noise Statistics) * ``GSV`` (Satellites in view) +* ``VTG`` (Track made good and Ground speed) -Adding support for more sentences is trivial; see ``minmea.c`` source. +Adding support for more sentences is trivial; see ``minmea.c`` source. Good documentation on NMEA is at http://www.catb.org/gpsd/NMEA.html ## Fractional number format diff --git a/example.c b/example.c index e4eebe4..665b18f 100644 --- a/example.c +++ b/example.c @@ -90,6 +90,23 @@ int main(void) } } break; + case MINMEA_SENTENCE_VTG: { + struct minmea_sentence_vtg frame; + if (minmea_parse_vtg(&frame, line)) { + printf(INDENT_SPACES "$xxVTG: true track degrees = %f\n", + minmea_tofloat(&frame.true_track_degrees)); + printf(INDENT_SPACES " magnetic track degrees = %f\n", + minmea_tofloat(&frame.magnetic_track_degrees)); + printf(INDENT_SPACES " speed knots = %f\n", + minmea_tofloat(&frame.speed_knots)); + printf(INDENT_SPACES " speed kph = %f\n", + minmea_tofloat(&frame.speed_kph)); + } + else { + printf(INDENT_SPACES "$xxVTG sentence is not parsed\n"); + } + } break; + case MINMEA_INVALID: { printf(INDENT_SPACES "$xxxxx sentence is not valid\n"); } break; diff --git a/minmea.c b/minmea.c index 9b23f1c..5566d95 100644 --- a/minmea.c +++ b/minmea.c @@ -369,6 +369,8 @@ enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict) return MINMEA_SENTENCE_GST; if (!strcmp(type+2, "GSV")) return MINMEA_SENTENCE_GSV; + if (!strcmp(type+2, "VTG")) + return MINMEA_SENTENCE_VTG; return MINMEA_UNKNOWN; } @@ -547,6 +549,40 @@ bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence) return true; } +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; +} + int minmea_gettime(struct timespec *ts, 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 6d7fe18..acbf182 100644 --- a/minmea.h +++ b/minmea.h @@ -31,6 +31,7 @@ enum minmea_sentence_id { MINMEA_SENTENCE_GLL, MINMEA_SENTENCE_GST, MINMEA_SENTENCE_GSV, + MINMEA_SENTENCE_VTG, }; struct minmea_float { @@ -79,10 +80,15 @@ enum minmea_gll_status { MINMEA_GLL_STATUS_DATA_NOT_VALID = 'V', }; -enum minmea_gll_mode { - MINMEA_GLL_MODE_AUTONOMOUS = 'A', - MINMEA_GLL_MODE_DPGS = 'D', - MINMEA_GLL_MODE_DR = 'E', +// FAA mode added to some fields in NMEA 2.3. +enum minmea_faa_mode { + MINMEA_FAA_MODE_AUTONOMOUS = 'A', + MINMEA_FAA_MODE_DIFFERENTIAL = 'D', + MINMEA_FAA_MODE_ESTIMATED = 'E', + MINMEA_FAA_MODE_MANUAL = 'M', + MINMEA_FAA_MODE_SIMULATED = 'S', + MINMEA_FAA_MODE_NOT_VALID = 'N', + MINMEA_FAA_MODE_PRECISE = 'P', }; struct minmea_sentence_gll { @@ -138,6 +144,14 @@ struct minmea_sentence_gsv { struct minmea_sat_info sats[4]; }; +struct minmea_sentence_vtg { + struct minmea_float true_track_degrees; + struct minmea_float magnetic_track_degrees; + struct minmea_float speed_knots; + struct minmea_float speed_kph; + enum minmea_faa_mode faa_mode; +}; + /** * Calculate raw sentence checksum. Does not check sentence integrity. */ @@ -180,6 +194,7 @@ bool minmea_parse_gsa(struct minmea_sentence_gsa *frame, const char *sentence); bool minmea_parse_gll(struct minmea_sentence_gll *frame, const char *sentence); bool minmea_parse_gst(struct minmea_sentence_gst *frame, const char *sentence); bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence); +bool minmea_parse_vtg(struct minmea_sentence_vtg *frame, const char *sentence); /** * Convert GPS UTC date/time representation to a UNIX timestamp. diff --git a/tests.c b/tests.c index b341107..f42baa1 100644 --- a/tests.c +++ b/tests.c @@ -569,14 +569,19 @@ END_TEST START_TEST(test_minmea_parse_gll1) { const char *sentence = "$GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41"; - struct minmea_sentence_gll frame = {}; - struct minmea_sentence_gll expected = { - .latitude = { 37232475, 10000 }, - .longitude = { -121583416, 10000 }, - .time = { 16, 12, 29, 487000 }, - .status = MINMEA_GLL_STATUS_DATA_VALID, - .mode = MINMEA_GLL_MODE_AUTONOMOUS, - }; + struct minmea_sentence_gll frame; + struct minmea_sentence_gll expected; + + // clear structs before initialization to enable use of memcmp() + // todo: add for other structs + memset(&frame, 0, sizeof(frame)); + memset(&expected, 0, sizeof(expected)); + + expected.latitude = (struct minmea_float){ 37232475, 10000 }; + expected.longitude = (struct minmea_float){ -121583416, 10000 }; + expected.time = (struct minmea_time){ 16, 12, 29, 487000 }; + expected.status = MINMEA_GLL_STATUS_DATA_VALID; + expected.mode = MINMEA_FAA_MODE_AUTONOMOUS; ck_assert(minmea_check(sentence, false) == true); ck_assert(minmea_check(sentence, true) == true); @@ -815,6 +820,50 @@ START_TEST(test_minmea_parse_gsv5) END_TEST +START_TEST(test_minmea_parse_vtg1) +{ + const char *sentence = "$GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48"; + // clear structs before initialization to enable use of memcmp() + struct minmea_sentence_vtg frame = {}; + struct minmea_sentence_vtg expected = {}; + + expected = (struct minmea_sentence_vtg){ + .true_track_degrees = { 547, 10 }, + .magnetic_track_degrees = { 344, 10 }, + .speed_knots = { 55, 10 }, + .speed_kph = { 102, 10 }, + .faa_mode = 0, + }; + + ck_assert(minmea_check(sentence, false) == true); + ck_assert(minmea_check(sentence, true) == true); + ck_assert(minmea_parse_vtg(&frame, sentence) == true); + ck_assert(!memcmp(&frame, &expected, sizeof(frame))); +} +END_TEST + +START_TEST(test_minmea_parse_vtg2) +{ + const char *sentence = "$GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F"; + // clear structs before initialization to enable use of memcmp() + struct minmea_sentence_vtg frame = {}; + struct minmea_sentence_vtg expected = {}; + + expected = (struct minmea_sentence_vtg){ + .true_track_degrees = { 18836, 100 }, + .magnetic_track_degrees = { 0, 0 }, + .speed_knots = { 820, 1000 }, + .speed_kph = { 1519, 1000 }, + .faa_mode = MINMEA_FAA_MODE_AUTONOMOUS, + }; + + ck_assert(minmea_check(sentence, false) == true); + ck_assert(minmea_check(sentence, true) == true); + ck_assert(minmea_parse_vtg(&frame, sentence) == true); + ck_assert(!memcmp(&frame, &expected, sizeof(frame))); +} +END_TEST + START_TEST(test_minmea_usage1) { const char *sentences[] = { @@ -823,6 +872,7 @@ START_TEST(test_minmea_usage1) "$GNGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1", "$GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41", "$GPGST,024603.00,3.2,6.6,4.7,47.3,5.8,5.6,22.0*58", + "$GPVTG,096.5,T,083.5,M,0.0,N,0.0,K,D*22", NULL, }; @@ -853,6 +903,11 @@ START_TEST(test_minmea_usage1) ck_assert(minmea_parse_gst(&frame, *sentence) == true); } break; + case MINMEA_SENTENCE_VTG: { + struct minmea_sentence_vtg frame; + ck_assert(minmea_parse_vtg(&frame, *sentence) == true); + } break; + default: { } break; } @@ -963,6 +1018,8 @@ static Suite *minmea_suite(void) tcase_add_test(tc_parse, test_minmea_parse_gsv3); tcase_add_test(tc_parse, test_minmea_parse_gsv4); tcase_add_test(tc_parse, test_minmea_parse_gsv5); + tcase_add_test(tc_parse, test_minmea_parse_vtg1); + tcase_add_test(tc_parse, test_minmea_parse_vtg2); suite_add_tcase(s, tc_parse); TCase *tc_usage = tcase_create("minmea_usage");