123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /*
- * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
- * 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.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <check.h>
- #include "minmea.h"
- static const char *valid_sequences[] = {
- "$GPTXT,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- "$GPTXT,01,01,02,ANTSTATUS=INIT*25",
- "$GPRMC,,V,,,,,,,,,,N*53",
- "$GPVTG,,,,,,,,,N*30",
- "$GPGGA,,,,,,0,00,99.99,,,,,,*48",
- "$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30",
- "$GPGLL,,,,,,V,N*64",
- "$GPXTE,A,A,0.67,L,N*6F",
- "$GPXTE,A,A,0.67,L,N*6f",
- "$GPGGA,123204.00,5106.94086,N,01701.51680,E,1,06,3.86,127.9,M,40.5,M,,*51",
- "$GPGSA,A,3,02,08,09,05,04,26,,,,,,,4.92,3.86,3.05*00",
- "$GPGSV,4,1,13,02,28,259,33,04,12,212,27,05,34,305,30,07,79,138,*7F",
- "$GPGSV,4,2,13,08,51,203,30,09,45,215,28,10,69,197,19,13,47,081,*76",
- "$GPGSV,4,3,13,16,20,040,17,26,08,271,30,28,01,168,18,33,24,219,27*74",
- "$GPGSV,4,4,13,39,31,170,27*40",
- "$GPGLL,5106.94086,N,01701.51680,E,123204.00,A,A*63",
- "$GPRMC,123205.00,A,5106.94085,N,01701.51689,E,0.016,,280214,,,A*7B",
- "$GPVTG,,T,,M,0.016,N,0.030,K,A*27",
- NULL,
- };
- static const char *invalid_sequences[] = {
- "$GPTXT,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
- "$GPTXT,01,01,02,ANTSTATUS=INIT*26",
- "$GPRMC,,V,,,,,,,,,,N*532",
- "$GPVTG,,,,\xff,,,,,N*30",
- "$$GPGGA,,,,,,0,00,99.99,,,,,,*48",
- "GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30",
- "gps: $GPGLL,,,,,,V,N",
- "$GPXTE,A,A,0.67,L,N*6e",
- "$GPXTE,A,A,0.67,L,N*6g",
- NULL,
- };
- START_TEST(test_minmea_check)
- {
- for (const char **sequence=valid_sequences; *sequence; sequence++)
- ck_assert_msg(minmea_check(*sequence) == true, *sequence);
- for (const char **sequence=invalid_sequences; *sequence; sequence++)
- ck_assert_msg(minmea_check(*sequence) == false, *sequence);
- }
- END_TEST
- START_TEST(test_minmea_scan_c)
- {
- char ch;
- ck_assert(minmea_scan("A,123.45", "c", &ch) == true);
- ck_assert_int_eq(ch, 'A');
- ck_assert(minmea_scan("WUT,123.45", "c", &ch) == true);
- ck_assert_int_eq(ch, 'W');
- ck_assert(minmea_scan(",123.45", "c", &ch) == true);
- ck_assert_int_eq(ch, '\0');
- }
- END_TEST
- START_TEST(test_minmea_scan_d)
- {
- int direction;
- ck_assert(minmea_scan("K", "d", &direction) == false);
- ck_assert(minmea_scan("", "d", &direction) == true);
- ck_assert(minmea_scan(",foo", "d", &direction) == true);
- ck_assert_int_eq(direction, 0);
- ck_assert(minmea_scan("N", "d", &direction) == true);
- ck_assert_int_eq(direction, 1);
- ck_assert(minmea_scan("S,foo", "d", &direction) == true);
- ck_assert_int_eq(direction, -1);
- ck_assert(minmea_scan("W", "d", &direction) == true);
- ck_assert_int_eq(direction, -1);
- ck_assert(minmea_scan("E,foo", "d", &direction) == true);
- ck_assert_int_eq(direction, 1);
- }
- END_TEST
- START_TEST(test_minmea_scan_f)
- {
- int value, scale;
- ck_assert(minmea_scan("-", "f", &value, &scale) == false);
- ck_assert(minmea_scan("10-", "f", &value, &scale) == false);
- ck_assert(minmea_scan("+-10", "f", &value, &scale) == false);
- ck_assert(minmea_scan("12..45", "f", &value, &scale) == false);
- ck_assert(minmea_scan("blah", "f", &value, &scale) == false);
- ck_assert(minmea_scan("12.3.4", "f", &value, &scale) == false);
- ck_assert(minmea_scan(",", "f", &value, &scale) == true);
- ck_assert_int_eq(scale, 0);
- ck_assert(minmea_scan("", "f", &value, &scale) == true);
- ck_assert_int_eq(scale, 0);
- ck_assert(minmea_scan("15.345", "f", &value, &scale) == true);
- ck_assert_int_eq(value, 15345);
- ck_assert_int_eq(scale, 1000);
- ck_assert(minmea_scan("-1.23,V", "f", &value, &scale) == true);
- ck_assert_int_eq(value, -123);
- ck_assert_int_eq(scale, 100);
- }
- END_TEST
- START_TEST(test_minmea_scan_s)
- {
- char value[MINMEA_MAX_LENGTH];
- ck_assert(minmea_scan("foo,bar,baz", "s", value) == true);
- ck_assert_str_eq(value, "foo");
- ck_assert(minmea_scan(",bar,baz", "s", value) == true);
- ck_assert_str_eq(value, "");
- }
- END_TEST
- START_TEST(test_minmea_scan_t)
- {
- char buf[7];
- buf[sizeof(buf)-1] = 0x42;
- ck_assert(minmea_scan("$GPRM,foo,bar,baz", "t", buf) == false);
- ck_assert(minmea_scan("GPRMC,foo,bar,baz", "t", buf) == false);
- ck_assert(minmea_scan("$GPRMC,foo,bar,baz", "t", buf) == true);
- ck_assert_str_eq(buf, "GPRMC");
- ck_assert(buf[sizeof(buf)-1] == 0x42);
- }
- END_TEST
- START_TEST(test_minmea_scan_D)
- {
- struct minmea_date date;
- ck_assert(minmea_scan("$GPXXX,311299", "_D", &date) == true);
- ck_assert_int_eq(date.day, 31);
- ck_assert_int_eq(date.month, 12);
- ck_assert_int_eq(date.year, 99);
- ck_assert(minmea_scan("$GPXXX,,,,,,,,,nope", "_D", &date) == true);
- ck_assert_int_eq(date.day, -1);
- ck_assert_int_eq(date.month, -1);
- ck_assert_int_eq(date.year, -1);
- }
- END_TEST
- START_TEST(test_minmea_scan_T)
- {
- struct minmea_time time;
- ck_assert(minmea_scan("$GPXXX,235960", "_T", &time) == true);
- ck_assert_int_eq(time.hours, 23);
- ck_assert_int_eq(time.minutes, 59);
- ck_assert_int_eq(time.seconds, 60);
- ck_assert_int_eq(time.microseconds, 0);
- ck_assert(minmea_scan("$GPXXX,213700.001", "_T", &time) == true);
- ck_assert_int_eq(time.hours, 21);
- ck_assert_int_eq(time.minutes, 37);
- ck_assert_int_eq(time.seconds, 0);
- ck_assert_int_eq(time.microseconds, 1000);
- ck_assert(minmea_scan("$GPXXX,,,,,,,nope", "_T", &time) == true);
- ck_assert_int_eq(time.hours, -1);
- ck_assert_int_eq(time.minutes, -1);
- ck_assert_int_eq(time.seconds, -1);
- ck_assert_int_eq(time.microseconds, -1);
- }
- END_TEST
- START_TEST(test_minmea_scan_complex1)
- {
- const char *sentence = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n";
- char type[6];
- struct minmea_time time;
- int latitude, latitude_scale, latitude_direction;
- int longitude, longitude_scale, longitude_direction;
- int fix_quality;
- int satellites;
- int hdop, hdop_scale;
- int altitude, altitude_scale; char altitude_units;
- int height, height_scale; char height_units;
- ck_assert(minmea_scan(sentence, "tTfdfdiiffcfc__",
- type,
- &time,
- &latitude, &latitude_scale, &latitude_direction,
- &longitude, &longitude_scale, &longitude_direction,
- &fix_quality,
- &satellites,
- &hdop, &hdop_scale,
- &altitude, &altitude_scale, &altitude_units,
- &height, &height_scale, &height_units) == true);
- ck_assert_str_eq(type, "GPGGA");
- ck_assert_int_eq(time.hours, 12);
- ck_assert_int_eq(time.minutes, 35);
- ck_assert_int_eq(time.seconds, 19);
- ck_assert_int_eq(latitude, 4807038);
- ck_assert_int_eq(latitude_scale, 1000);
- ck_assert_int_eq(latitude_direction, 1);
- ck_assert_int_eq(longitude, 1131000);
- ck_assert_int_eq(longitude_scale, 1000);
- ck_assert_int_eq(longitude_direction, 1);
- ck_assert_int_eq(fix_quality, 1);
- ck_assert_int_eq(satellites, 8);
- ck_assert_int_eq(hdop, 9);
- ck_assert_int_eq(hdop_scale, 10);
- ck_assert_int_eq(altitude, 5454);
- ck_assert_int_eq(altitude_scale, 10);
- ck_assert_int_eq(altitude_units, 'M');
- ck_assert_int_eq(height, 469);
- ck_assert_int_eq(height_scale, 10);
- ck_assert_int_eq(height_units, 'M');
- }
- END_TEST
- START_TEST(test_minmea_scan_complex2)
- {
- const char *sentence = "$GPBWC,081837,,,,,,T,,M,,N,*13";
- char type[6];
- struct minmea_time time;
- int latitude, latitude_scale, latitude_direction;
- int longitude, longitude_scale, longitude_direction;
- int bearing_true, bearing_true_scale; char bearing_true_mark;
- int bearing_magnetic, bearing_magnetic_scale; char bearing_magnetic_mark;
- int distance, distance_scale; char distance_units;
- char name[MINMEA_MAX_LENGTH];
- ck_assert(minmea_scan(sentence, "tTfdfdfcfcfcs",
- type,
- &time,
- &latitude, &latitude_scale, &latitude_direction,
- &longitude, &longitude_scale, &longitude_direction,
- &bearing_true, &bearing_true_scale, &bearing_true_mark,
- &bearing_magnetic, &bearing_magnetic_scale, &bearing_magnetic_mark,
- &distance, &distance_scale, &distance_units,
- name) == true);
- ck_assert_str_eq(type, "GPBWC");
- ck_assert_int_eq(time.hours, 8);
- ck_assert_int_eq(time.minutes, 18);
- ck_assert_int_eq(time.seconds, 37);
- ck_assert_int_eq(latitude_scale, 0);
- ck_assert_int_eq(latitude_direction, 0);
- ck_assert_int_eq(longitude_scale, 0);
- ck_assert_int_eq(longitude_direction, 0);
- ck_assert_int_eq(bearing_true_scale, 0);
- ck_assert_int_eq(bearing_true_mark, 'T');
- ck_assert_int_eq(bearing_magnetic_scale, 0);
- ck_assert_int_eq(bearing_magnetic_mark, 'M');
- ck_assert_int_eq(distance_scale, 0);
- ck_assert_int_eq(distance_units, 'N');
- ck_assert_str_eq(name, "");
- }
- END_TEST
- START_TEST(test_minmea_parse_gprmc1)
- {
- const char *sentence = "$GPRMC,081836.75,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E";
- struct minmea_gprmc frame = {};
- struct minmea_gprmc expected = {
- .time = { 8, 18, 36, 750000 },
- .valid = true,
- .latitude = -375165,
- .latitude_scale = 100,
- .longitude = 1450736,
- .longitude_scale = 100,
- .speed = 0,
- .speed_scale = 10,
- .course = 3600,
- .course_scale = 10,
- .date = { 13, 9, 98 },
- .variation = 113,
- .variation_scale = 10,
- };
- ck_assert(minmea_check(sentence) == true);
- ck_assert(minmea_parse_gprmc(&frame, sentence) == true);
- ck_assert(!memcmp(&frame, &expected, sizeof(frame)));
- }
- END_TEST
- START_TEST(test_minmea_parse_gprmc2)
- {
- const char *sentence = "$GPRMC,,A,3751.65,N,14507.36,W,,,,,";
- struct minmea_gprmc frame = {};
- struct minmea_gprmc expected = {
- .time = { -1, -1, -1, -1 },
- .valid = true,
- .latitude = 375165,
- .latitude_scale = 100,
- .longitude = -1450736,
- .longitude_scale = 100,
- .date = { -1, -1, -1 },
- };
- ck_assert(minmea_check(sentence) == true);
- ck_assert(minmea_parse_gprmc(&frame, sentence) == true);
- ck_assert(!memcmp(&frame, &expected, sizeof(frame)));
- }
- END_TEST
- START_TEST(test_minmea_parse_gpgga1)
- {
- const char *sentence = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47";
- struct minmea_gpgga frame = {};
- struct minmea_gpgga expected = {
- .time = { 12, 35, 19, 0 },
- .latitude = 4807038,
- .latitude_scale = 1000,
- .longitude = 1131000,
- .longitude_scale = 1000,
- .fix_quality = 1,
- .satellites_tracked = 8,
- .hdop = 9,
- .hdop_scale = 10,
- .altitude = 5454,
- .altitude_scale = 10,
- .altitude_units = 'M',
- .height = 469,
- .height_scale = 10,
- .height_units = 'M',
- .dgps_age = 0,
- };
- ck_assert(minmea_check(sentence) == true);
- ck_assert(minmea_parse_gpgga(&frame, sentence) == true);
- ck_assert(!memcmp(&frame, &expected, sizeof(frame)));
- }
- 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 = MINMEA_GPGSA_MODE_AUTO,
- .fix_type = MINMEA_GPGSA_FIX_3D,
- .sats = { 4, 5, 0, 9, 12, 0, 0, 24, 0, 0, 0, 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,
- };
- for (const char **sentence=sentences; *sentence; sentence++) {
- switch (minmea_type(*sentence)) {
- case MINMEA_GPRMC: {
- struct minmea_gprmc frame;
- ck_assert(minmea_parse_gprmc(&frame, *sentence) == true);
- } break;
-
- case MINMEA_GPGGA: {
- struct minmea_gpgga frame;
- 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;
- }
- }
- }
- END_TEST
- START_TEST(test_minmea_gettimeofday)
- {
- struct minmea_date date = { 14, 2, 14 };
- struct minmea_time time = { 13, 0, 9, 123456 };
- struct timeval tv;
- ck_assert(minmea_gettimeofday(&tv, &date, &time) == 0);
- ck_assert_int_eq(tv.tv_sec, 1392382809);
- ck_assert_int_eq(tv.tv_usec, 123456);
- date.year = -1;
- ck_assert(minmea_gettimeofday(&tv, &date, &time) != 0);
- date.year = 2014;
- time.hours = -1;
- ck_assert(minmea_gettimeofday(&tv, &date, &time) != 0);
- }
- END_TEST
- START_TEST(test_minmea_rescale)
- {
- /* basic and edge cases. */
- ck_assert_int_eq(minmea_rescale(42, 0, 3), 0);
- ck_assert_int_eq(minmea_rescale(1234, 10, 1), 123);
- ck_assert_int_eq(minmea_rescale(1235, 10, 1), 124);
- ck_assert_int_eq(minmea_rescale(1234, 10, 1000), 123400);
- /* round towards zero. */
- ck_assert_int_eq(minmea_rescale(-1234, 10, 1), -123);
- ck_assert_int_eq(minmea_rescale(-1235, 10, 1), -124);
- ck_assert_int_eq(minmea_rescale(-1236, 10, 1), -124);
- /* shouldn't overflow on large numbers. */
- ck_assert_int_eq(minmea_rescale(510693608, 100000, 10000), 51069361);
- }
- END_TEST
- START_TEST(test_minmea_float)
- {
- ck_assert(isnan(minmea_float(42, 0)));
- ck_assert(minmea_float(7, 1) == 7.0);
- ck_assert(minmea_float(-200, 100) == -2.0);
- ck_assert(minmea_float(15, 10) == 1.5);
- }
- END_TEST
- START_TEST(test_minmea_coord)
- {
- ck_assert(isnan(minmea_coord(42, 0)));
- ck_assert(minmea_coord(4200, 1) == 42.0);
- ck_assert(minmea_coord(420000, 100) == 42.0);
- ck_assert(minmea_coord(423000, 100) == 42.5);
- }
- END_TEST
- Suite *minmea_suite(void)
- {
- Suite *s = suite_create ("minmea");
-
- TCase *tc_check = tcase_create("minmea_check");
- tcase_add_test(tc_check, test_minmea_check);
- suite_add_tcase(s, tc_check);
- TCase *tc_scan = tcase_create("minmea_scan");
- tcase_add_test(tc_scan, test_minmea_scan_c);
- tcase_add_test(tc_scan, test_minmea_scan_d);
- tcase_add_test(tc_scan, test_minmea_scan_f);
- tcase_add_test(tc_scan, test_minmea_scan_s);
- tcase_add_test(tc_scan, test_minmea_scan_t);
- tcase_add_test(tc_scan, test_minmea_scan_D);
- tcase_add_test(tc_scan, test_minmea_scan_T);
- tcase_add_test(tc_scan, test_minmea_scan_complex1);
- tcase_add_test(tc_scan, test_minmea_scan_complex2);
- suite_add_tcase(s, tc_scan);
-
- TCase *tc_parse = tcase_create("minmea_parse");
- 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");
- tcase_add_test(tc_usage, test_minmea_usage1);
- suite_add_tcase(s, tc_usage);
- TCase *tc_utils = tcase_create("minmea_utils");
- tcase_add_test(tc_utils, test_minmea_gettimeofday);
- tcase_add_test(tc_utils, test_minmea_rescale);
- tcase_add_test(tc_utils, test_minmea_float);
- tcase_add_test(tc_utils, test_minmea_coord);
- suite_add_tcase(s, tc_utils);
- return s;
- }
- int main()
- {
- int number_failed;
- Suite *s = minmea_suite();
- SRunner *sr = srunner_create(s);
- srunner_run_all(sr, CK_NORMAL);
- number_failed = srunner_ntests_failed(sr);
- srunner_free(sr);
- return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
- }
- /* vim: set ts=4 sw=4 et: */
|