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.
This commit is contained in:
lvitya 2016-04-23 22:19:26 +03:00 committed by Artur Mądrzak
parent ade6621a59
commit 95f6beec4f
5 changed files with 139 additions and 13 deletions

View File

@ -24,8 +24,9 @@ systems.
* ``GLL`` (Geographic Position: Latitude/Longitude) * ``GLL`` (Geographic Position: Latitude/Longitude)
* ``GST`` (Pseudorange Noise Statistics) * ``GST`` (Pseudorange Noise Statistics)
* ``GSV`` (Satellites in view) * ``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 ## Fractional number format

View File

@ -90,6 +90,23 @@ int main(void)
} }
} break; } 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: { case MINMEA_INVALID: {
printf(INDENT_SPACES "$xxxxx sentence is not valid\n"); printf(INDENT_SPACES "$xxxxx sentence is not valid\n");
} break; } break;

View File

@ -369,6 +369,8 @@ enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict)
return MINMEA_SENTENCE_GST; return MINMEA_SENTENCE_GST;
if (!strcmp(type+2, "GSV")) if (!strcmp(type+2, "GSV"))
return MINMEA_SENTENCE_GSV; return MINMEA_SENTENCE_GSV;
if (!strcmp(type+2, "VTG"))
return MINMEA_SENTENCE_VTG;
return MINMEA_UNKNOWN; return MINMEA_UNKNOWN;
} }
@ -547,6 +549,40 @@ bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence)
return true; 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_) int minmea_gettime(struct timespec *ts, const struct minmea_date *date, const struct minmea_time *time_)
{ {
if (date->year == -1 || time_->hours == -1) if (date->year == -1 || time_->hours == -1)

View File

@ -31,6 +31,7 @@ enum minmea_sentence_id {
MINMEA_SENTENCE_GLL, MINMEA_SENTENCE_GLL,
MINMEA_SENTENCE_GST, MINMEA_SENTENCE_GST,
MINMEA_SENTENCE_GSV, MINMEA_SENTENCE_GSV,
MINMEA_SENTENCE_VTG,
}; };
struct minmea_float { struct minmea_float {
@ -79,10 +80,15 @@ enum minmea_gll_status {
MINMEA_GLL_STATUS_DATA_NOT_VALID = 'V', MINMEA_GLL_STATUS_DATA_NOT_VALID = 'V',
}; };
enum minmea_gll_mode { // FAA mode added to some fields in NMEA 2.3.
MINMEA_GLL_MODE_AUTONOMOUS = 'A', enum minmea_faa_mode {
MINMEA_GLL_MODE_DPGS = 'D', MINMEA_FAA_MODE_AUTONOMOUS = 'A',
MINMEA_GLL_MODE_DR = 'E', 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 { struct minmea_sentence_gll {
@ -138,6 +144,14 @@ struct minmea_sentence_gsv {
struct minmea_sat_info sats[4]; 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. * 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_gll(struct minmea_sentence_gll *frame, const char *sentence);
bool minmea_parse_gst(struct minmea_sentence_gst *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_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. * Convert GPS UTC date/time representation to a UNIX timestamp.

73
tests.c
View File

@ -569,14 +569,19 @@ END_TEST
START_TEST(test_minmea_parse_gll1) START_TEST(test_minmea_parse_gll1)
{ {
const char *sentence = "$GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41"; const char *sentence = "$GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41";
struct minmea_sentence_gll frame = {}; struct minmea_sentence_gll frame;
struct minmea_sentence_gll expected = { struct minmea_sentence_gll expected;
.latitude = { 37232475, 10000 },
.longitude = { -121583416, 10000 }, // clear structs before initialization to enable use of memcmp()
.time = { 16, 12, 29, 487000 }, // todo: add for other structs
.status = MINMEA_GLL_STATUS_DATA_VALID, memset(&frame, 0, sizeof(frame));
.mode = MINMEA_GLL_MODE_AUTONOMOUS, 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, false) == true);
ck_assert(minmea_check(sentence, true) == true); ck_assert(minmea_check(sentence, true) == true);
@ -815,6 +820,50 @@ START_TEST(test_minmea_parse_gsv5)
END_TEST 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) START_TEST(test_minmea_usage1)
{ {
const char *sentences[] = { 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", "$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", "$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", "$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, NULL,
}; };
@ -853,6 +903,11 @@ START_TEST(test_minmea_usage1)
ck_assert(minmea_parse_gst(&frame, *sentence) == true); ck_assert(minmea_parse_gst(&frame, *sentence) == true);
} break; } break;
case MINMEA_SENTENCE_VTG: {
struct minmea_sentence_vtg frame;
ck_assert(minmea_parse_vtg(&frame, *sentence) == true);
} break;
default: { default: {
} break; } 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_gsv3);
tcase_add_test(tc_parse, test_minmea_parse_gsv4); 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_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); suite_add_tcase(s, tc_parse);
TCase *tc_usage = tcase_create("minmea_usage"); TCase *tc_usage = tcase_create("minmea_usage");