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:
parent
ade6621a59
commit
95f6beec4f
@ -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
|
||||||
|
|
||||||
|
17
example.c
17
example.c
@ -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;
|
||||||
|
36
minmea.c
36
minmea.c
@ -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)
|
||||||
|
23
minmea.h
23
minmea.h
@ -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
73
tests.c
@ -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");
|
||||||
|
Loading…
Reference in New Issue
Block a user