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_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) { 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); }
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; }
bool minmea_parse_gga(struct minmea_sentence_gga *frame, const char *sentence) { // $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47 char type[6]; int latitude_direction; int longitude_direction; if (!minmea_scan(sentence, "tTfdfdiiffcfci_", type, &frame->time, &frame->latitude, &latitude_direction, &frame->longitude, &longitude_direction, &frame->fix_quality, &frame->satellites_tracked, &frame->hdop, &frame->altitude, &frame->altitude_units, &frame->height, &frame->height_units, &frame->dgps_age)) return false; if (strcmp(type+2, "GGA")) return false; frame->latitude.value *= latitude_direction; frame->longitude.value *= longitude_direction; return true; }
bool minmea_parse_gsa(struct minmea_sentence_gsa *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->sats[0], &frame->sats[1], &frame->sats[2], &frame->sats[3], &frame->sats[4], &frame->sats[5], &frame->sats[6], &frame->sats[7], &frame->sats[8], &frame->sats[9], &frame->sats[10], &frame->sats[11], &frame->pdop, &frame->hdop, &frame->vdop)) return false; if (strcmp(type+2, "GSA")) return false; return true; }
enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict) { if (!minmea_check(sentence, strict)) return MINMEA_INVALID; char type[6]; if (!minmea_scan(sentence, "t", type)) return MINMEA_INVALID; if (!strcmp(type+2, "RMC")) return MINMEA_SENTENCE_RMC; if (!strcmp(type+2, "GGA")) return MINMEA_SENTENCE_GGA; if (!strcmp(type+2, "GSA")) return MINMEA_SENTENCE_GSA; if (!strcmp(type+2, "GLL")) return MINMEA_SENTENCE_GLL; if (!strcmp(type+2, "GST")) 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; }
bool minmea_parse_rmc(struct minmea_sentence_rmc *frame, const char *sentence) { // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 char type[6]; char validity; int latitude_direction; int longitude_direction; int variation_direction; if (!minmea_scan(sentence, "tTcfdfdffDfd", type, &frame->time, &validity, &frame->latitude, &latitude_direction, &frame->longitude, &longitude_direction, &frame->speed, &frame->course, &frame->date, &frame->variation, &variation_direction)) return false; if (strcmp(type+2, "RMC")) return false; frame->valid = (validity == 'A'); frame->latitude.value *= latitude_direction; frame->longitude.value *= longitude_direction; frame->variation.value *= variation_direction; return true; }
bool minmea_parse_zda(struct minmea_sentence_zda *frame, const char *sentence) { // $GPZDA,201530.00,04,07,2002,00,00*60 char type[6]; if(!minmea_scan(sentence, "tTiiiii", type, &frame->time, &frame->date.day, &frame->date.month, &frame->date.year, &frame->hour_offset, &frame->minute_offset)) return false; if (strcmp(type+2, "ZDA")) return false; // check offsets if (abs(frame->hour_offset) > 13 || frame->minute_offset > 59 || frame->minute_offset < 0) return false; return true; }
bool minmea_talker_id(char talker[3], const char *sentence) { char type[6]; if (!minmea_scan(sentence, "t", type)) return false; talker[0] = type[0]; talker[1] = type[1]; talker[2] = '\0'; return true; }
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_complex3) { const char *sentence = "$GPGST,024603.00,3.2,6.6,4.7,47.3,5.8,5.6,22.0*58"; char type[6]; struct minmea_time time; int rms_deviation, rms_deviation_scale; int semi_major_deviation, semi_major_deviation_scale; int semi_minor_deviation, semi_minor_deviation_scale; int semi_major_orientation, semi_major_orientation_scale; int latitude_error_deviation, latitude_error_deviation_scale; int longitude_error_deviation, longitude_error_deviation_scale; int altitude_error_deviation, altitude_error_deviation_scale; ck_assert(minmea_scan(sentence, "tTfffffff", type, &time, &rms_deviation, &rms_deviation_scale, &semi_major_deviation, &semi_major_deviation_scale, &semi_minor_deviation, &semi_minor_deviation_scale, &semi_major_orientation, &semi_major_orientation_scale, &latitude_error_deviation, &latitude_error_deviation_scale, &longitude_error_deviation, &longitude_error_deviation_scale, &altitude_error_deviation, &altitude_error_deviation_scale) == true); ck_assert_str_eq(type, "GPGST"); ck_assert_int_eq(time.hours, 2); ck_assert_int_eq(time.minutes, 46); ck_assert_int_eq(time.seconds, 3); ck_assert_int_eq(time.microseconds, 0); ck_assert_int_eq(rms_deviation, 32); ck_assert_int_eq(rms_deviation_scale, 10); ck_assert_int_eq(semi_major_deviation, 66); ck_assert_int_eq(semi_major_deviation_scale, 10); ck_assert_int_eq(semi_minor_deviation, 47); ck_assert_int_eq(semi_minor_deviation_scale, 10); ck_assert_int_eq(semi_major_orientation, 473); ck_assert_int_eq(semi_major_orientation_scale, 10); ck_assert_int_eq(latitude_error_deviation, 58); ck_assert_int_eq(latitude_error_deviation, 10); ck_assert_int_eq(longitude_error_deviation, 56); ck_assert_int_eq(longitude_error_deviation, 10); ck_assert_int_eq(altitude_error_deviation, 220); ck_assert_int_eq(altitude_error_deviation_scale,10); }
bool minmea_parse_gst(struct minmea_sentence_gst *frame, const char *sentence) { // $GPGST,024603.00,3.2,6.6,4.7,47.3,5.8,5.6,22.0*58 char type[6]; if (!minmea_scan(sentence, "tTfffffff", type, &frame->time, &frame->rms_deviation, &frame->semi_major_deviation, &frame->semi_minor_deviation, &frame->semi_major_orientation, &frame->latitude_error_deviation, &frame->longitude_error_deviation, &frame->altitude_error_deviation)) return false; if (strcmp(type+2, "GST")) return false; return true; }
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); }
bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence) { // $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74 // $GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D // $GPGSV,4,2,11,08,51,203,30,09,45,215,28*75 // $GPGSV,4,4,13,39,31,170,27*40 // $GPGSV,4,4,13*7B char type[6]; if (!minmea_scan(sentence, "tiii;iiiiiiiiiiiiiiii", type, &frame->total_msgs, &frame->msg_nr, &frame->total_sats, &frame->sats[0].nr, &frame->sats[0].elevation, &frame->sats[0].azimuth, &frame->sats[0].snr, &frame->sats[1].nr, &frame->sats[1].elevation, &frame->sats[1].azimuth, &frame->sats[1].snr, &frame->sats[2].nr, &frame->sats[2].elevation, &frame->sats[2].azimuth, &frame->sats[2].snr, &frame->sats[3].nr, &frame->sats[3].elevation, &frame->sats[3].azimuth, &frame->sats[3].snr )) { return false; } if (strcmp(type+2, "GSV")) return false; return true; }
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, ""); }
bool minmea_parse_gll(struct minmea_sentence_gll *frame, const char *sentence) { // $GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41$; char type[6]; int latitude_direction; int longitude_direction; if (!minmea_scan(sentence, "tfdfdTc;c", type, &frame->latitude, &latitude_direction, &frame->longitude, &longitude_direction, &frame->time, &frame->status, &frame->mode)) return false; if (strcmp(type+2, "GLL")) return false; frame->latitude.value *= latitude_direction; frame->longitude.value *= longitude_direction; return true; }
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); /* some GPS units have absurdly big precision. handle whatever int handles. */ ck_assert(minmea_scan("5106.94091", "f", &value, &scale) == true); ck_assert_int_eq(value, 510694091); ck_assert_int_eq(scale, 100000); /* for now we support +-180 degrees with 5 decimal digits; anything * more will overflow. */ ck_assert(minmea_scan("18000.00000", "f", &value, &scale) == true); ck_assert_int_eq(value, 1800000000); ck_assert_int_eq(scale, 100000); ck_assert(minmea_scan("-18000.00000", "f", &value, &scale) == true); ck_assert_int_eq(value, -1800000000); ck_assert_int_eq(scale, 100000); }