123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- /*
- * =====================================================================================
- *
- * Filename: nmeaparser.c
- *
- * Description: Nmea parser source file
- *
- * Version: 1.0
- * Created: 2018/8/15 17:43:35
- * Revision: none
- * Compiler: gcc
- *
- * Author: Jarod Lee(),
- * Organization:
- *
- * =====================================================================================
- */
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include <math.h>
- #include "nmeaparser.h"
- /*
- * Convert nmea string to integer
- * @p: nmea string start ptr
- * @end: nmea string end ptr
- * @return: the integer value
- */
- static int str2int(const char *p, const char *end) {
- int result = 0;
- while(p < end)
- {
- int c = *p - '0';
- if ((unsigned)c >= 10) {
- return -1;
- }
- result = result * 10 + c;
- p++;
- }
- return result;
- }
- /*
- * Convert nmea string to float
- * @p: nmea string start ptr
- * @end: nmea string end ptr
- * @return: the float value
- */
- static double str2float(const char *p, const char *end) {
- int len = end - p;
- char temp[16];
- if (len >= (int)sizeof(temp))
- return 0.;
- memcpy( temp, p, len );
- temp[len] = 0;
- return strtod( temp, NULL );
- }
- /*
- * Convert nmea's latitude or longitude token to degrees
- * @tok: latitude or longitude token
- * @return: latitude or longitude in degrees
- */
- static double convert_from_hhmm(struct token tok) {
- double val = str2float(tok.p, tok.end);
- int degrees = (int)(floor(val) / 100);
- double minutes = val - degrees*100.;
- double dcoord = degrees + minutes / 60.0;
- return dcoord;
- }
- /*
- * Convert nmea's latitude to degrees
- * @lat_tok: nmea latitude token
- * @lat_hemi: 'N' means positive while 'S' means negative
- */
- static double convert_latitude(struct token lat_tok, char lat_hemi)
- {
- double lat = convert_from_hhmm(lat_tok);
- return (lat_hemi == 'N' ? 1 : -1) * lat;
- }
- /*
- * Convert nmea's longitude to degrees
- * @lon_tok: nmea longitude token
- * @lon_hemi: 'E' means positive while 'W' means negative
- */
- static double convert_longitude(struct token lon_tok, char lon_hemi)
- {
- double lon = convert_from_hhmm(lon_tok);
- return (lon_hemi == 'E' ? 1 : -1) * lon;
- }
- /*
- * Convert nmea time token to gnss time struct
- * @tok: nmea's time token
- * @return: gnss_time structure
- */
- static struct gnss_time convert_gnss_time(struct token tok)
- {
- // HHMMSS.MS: 101943.235-> 10:19:43.235 -> hour = 10, minute = 19, second = 43, ms = 235
- double val = str2float(tok.p, tok.end);
- struct gnss_time time;
- memset(&time, 0, sizeof(struct gnss_time));
- time.hour = (int)(val / 10000);
- time.minute = (int)(val / 100) % 100;
- time.second = ((int)val) % 100;
- time.ms = (int)(0.5 + 1000 * (val - floor(val)));
- return time;
- }
- /*
- * Convert nmea date token into gnss_date struct
- * @tok: nmea's date token in RMC
- * @return: gnss_date structure
- */
- static struct gnss_date convert_gnss_date(struct token tok)
- {
- int val = str2int(tok.p, tok.end);
- struct gnss_date date;
- memset(&date, 0, sizeof(struct gnss_date));
- date.year = 2000 + (val % 100);
- date.month = (val / 100) % 100;
- date.day = (int)(val / 10000);
- return date;
- }
- /*
- * Get constellation type by nmea sentence token
- * @p: ptr to nmea's sentence start
- * @return: constellation type
- */
- static int get_sv_constell(char *p)
- {
- if (0 == memcmp(p, "GP", 2))
- return CONSTELL_TYPE_GPS;
- else if (0 == memcmp(p, "GL", 2))
- return CONSTELL_TYPE_GLN;
- else if (0 == memcmp(p, "BD", 2))
- return CONSTELL_TYPE_BDS;
- return CONSTELL_TYPE_UNKNOWN;
- }
- /*
- * Is the quality means fixed.
- * @quality: fix flag in GGA
- * @return: true for fixed, false for not fixed
- */
- static bool is_quality_fixed(char quality) {
- switch(quality) {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- return true;
- default:
- return false;
- }
- }
- /*
- * Is the mode means fixed
- * @mode: fix flag in RMC
- * @return: true for fixed, false for not fixed
- */
- static bool is_mode_fixed(char mode)
- {
- switch(mode) {
- case 'A':
- case 'D':
- case 'E':
- return true;
- default:
- return false;
- }
- }
- /*
- * Parse GGA, store the parsed data in navigation data
- * @tzer: current tokenizer
- * @navdata: navigation data
- */
- void parse_gga(struct nmea_tokenizer *tzer, struct nav_data *navdata)
- {
- struct token tok_time = nmea_tokenizer_get(tzer, 1);
- struct token tok_latitude = nmea_tokenizer_get(tzer, 2);
- struct token tok_latitudeHemi = nmea_tokenizer_get(tzer, 3);
- struct token tok_longitude = nmea_tokenizer_get(tzer, 4);
- struct token tok_longitudeHemi = nmea_tokenizer_get(tzer, 5);
- struct token tok_fixQuality = nmea_tokenizer_get(tzer, 6);
- struct token tok_svNumInUse = nmea_tokenizer_get(tzer, 7);
- struct token tok_hdop = nmea_tokenizer_get(tzer, 8);
- struct token tok_altitude = nmea_tokenizer_get(tzer, 9);
- navdata->is_fixed = is_quality_fixed(tok_fixQuality.p[0]);
- if (navdata->is_fixed) {
- navdata->time = convert_gnss_time(tok_time);
- navdata->lat = convert_latitude(tok_latitude, tok_latitudeHemi.p[0]);
- navdata->lon = convert_longitude(tok_longitude, tok_longitudeHemi.p[0]);
- navdata->sv_inuse = str2int(tok_svNumInUse.p, tok_svNumInUse.end);
- navdata->hdop = str2float(tok_hdop.p, tok_hdop.end);
- navdata->alt = str2float(tok_altitude.p, tok_altitude.end);
- }
- }
- /*
- * Parse RMC, store the parsed data in navigation data
- * @tzer: current tokenizer
- * @navdata: navigation data
- */
- void parse_rmc(struct nmea_tokenizer *tzer, struct nav_data *navdata) {
- struct token tok_time = nmea_tokenizer_get(tzer,1);
- struct token tok_dataValid = nmea_tokenizer_get(tzer,2);
- struct token tok_latitude = nmea_tokenizer_get(tzer,3);
- struct token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
- struct token tok_longitude = nmea_tokenizer_get(tzer,5);
- struct token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
- struct token tok_speed = nmea_tokenizer_get(tzer,7);
- struct token tok_heading = nmea_tokenizer_get(tzer,8);
- struct token tok_date = nmea_tokenizer_get(tzer,9);
- struct token tok_fixMode = nmea_tokenizer_get(tzer,12);
- navdata->is_fixed = is_mode_fixed(tok_fixMode.p[0]);
- if (navdata->is_fixed) {
- navdata->time = convert_gnss_time(tok_time);
- navdata->lat = convert_latitude(tok_latitude, tok_latitudeHemi.p[0]);
- navdata->lon = convert_longitude(tok_longitude, tok_longitudeHemi.p[0]);
- navdata->speed = str2float(tok_speed.p, tok_speed.end);
- navdata->heading = str2float(tok_heading.p, tok_heading.end);
- }
- if (tok_dataValid.p[0] == 'A')
- navdata->date = convert_gnss_date(tok_date);
- }
- /*
- * Parse GSA, store the parsed data in navigation data
- * @tzer: current tokenizer
- * @navdata: navigation data
- */
- void parse_gsa(struct nmea_tokenizer *tzer, struct nav_data *navdata) {
- struct token tok_id = nmea_tokenizer_get(tzer, 0);
- struct token tok_pdop = nmea_tokenizer_get(tzer, 15);
- struct token tok_hdop = nmea_tokenizer_get(tzer, 16);
- struct token tok_vdop = nmea_tokenizer_get(tzer, 17);
- struct token tok_svs = nmea_tokenizer_get(tzer, 18);
- int constell = get_sv_constell(tok_id.p);
- switch(tok_svs.p[0]) {
- case '1':
- constell = CONSTELL_TYPE_GPS;
- break;
- case '2':
- constell = CONSTELL_TYPE_GLN;
- break;
- case '4':
- constell = CONSTELL_TYPE_BDS;
- break;
- default:
- break;
- }
- int i;
- for (i = 3; i <= 14; i++) {
- struct token tok_prn = nmea_tokenizer_get(tzer, i);
- int svid = prn2svid(str2int(tok_prn.p, tok_prn.end), constell);
- if (svid > 0 && svid < MAX_SVID) {
- navdata->sates[svid].in_use = true;
- }
- }
- navdata->pdop = str2float(tok_pdop.p, tok_pdop.end);
- navdata->hdop = str2float(tok_hdop.p, tok_hdop.end);
- navdata->vdop = str2float(tok_vdop.p, tok_vdop.end);
- }
- /*
- * Parse GSV, store the parsed data in navigation data
- * @tzer: current tokenizer
- * @navdata: navigation data
- */
- void parse_gsv(struct nmea_tokenizer *tzer, struct nav_data *d) {
- struct token tok_id = nmea_tokenizer_get(tzer, 0);
- struct token tok_noSentences = nmea_tokenizer_get(tzer, 1);
- struct token tok_sentence = nmea_tokenizer_get(tzer, 2);
- struct token tok_noSatellites = nmea_tokenizer_get(tzer, 3);
- int constell = get_sv_constell(tok_id.p);
- int noSatellites = str2int(tok_noSatellites.p, tok_noSatellites.end);
- int sentence = str2int(tok_sentence.p, tok_sentence.end);
- int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);
- if (sentence == 1)
- d->sv_count = 0;
- if (noSatellites > 0) {
- int i = 0;
- while (i < 4 && d->sv_count < noSatellites) {
- struct token tok_prn = nmea_tokenizer_get(tzer, i * 4 + 4);
- struct token tok_elevation = nmea_tokenizer_get(tzer, i * 4 + 5);
- struct token tok_azimuth = nmea_tokenizer_get(tzer, i * 4 + 6);
- struct token tok_snr = nmea_tokenizer_get(tzer, i * 4 + 7);
- int prn = str2int(tok_prn.p, tok_prn.end);
- int svid = prn2svid(prn, constell);
- if (svid > 0 && svid < MAX_SVID) {
- d->sates[svid].prn = prn;
- d->sates[svid].elev = str2float(tok_elevation.p, tok_elevation.end);
- d->sates[svid].azim = str2float(tok_azimuth.p, tok_azimuth.end);
- d->sates[svid].cn0 = str2float(tok_snr.p, tok_snr.end);
- d->sates[svid].valid = 1;
- d->sates[svid].constell = tell_constell(svid);
- }
- d->sv_count++;
- d->sv_inview++;
- i += 1;
- }
- }
- if (sentence == totalSentences)
- d->sv_count = 0;
- }
- /*
- * Parse current nmea sentence
- */
- void parse(struct nmea_tokenizer *tzer, struct nav_data *navdata, void (*reporter)(struct nav_data *)) {
- struct token tok = nmea_tokenizer_get(tzer, 0);
- tok.p += 2;
- // display and reset nav_data if encounter GGA sentence
- if (memcmp(tok.p, "GGA", 3) == 0) {
- // navdata_display(navdata);
- if (reporter)
- reporter(navdata);
-
- navdata_init(navdata);
- }
- if (memcmp(tok.p, "GGA", 3) == 0) { // parse GGA
- parse_gga(tzer, navdata);
- }
- else if (memcmp(tok.p, "RMC", 3) == 0) { // parse RMC
- parse_rmc(tzer, navdata);
- }
- else if (memcmp(tok.p, "GSA", 3) == 0) { // parse GSA
- parse_gsa(tzer, navdata);
- }
- else if (memcmp(tok.p, "GSV", 3) == 0) { // parse GSV
- parse_gsv(tzer, navdata);
- }
- }
- /*
- * Init nmea parser
- */
- void nmea_parser_init(struct nmea_parser *p)
- {
- memset(p, 0, sizeof(*p));
- }
- /*
- * Put one char into nmea parser
- * @p: nmea_parser
- * @c: the character placed into nmea parser
- */
- void nmea_parser_putchar(struct nmea_parser *p, char c)
- {
- nmea_reader_add(p->reader, c);
- if (c == '\n') {
- if (nmea_reader_check(p->reader)) {
- nmea_tokenizer_init(p->tzer, p->reader->buf, p->reader->buf + p->reader->pos);
- parse(p->tzer, p->data, p->report_nav_status);
- }
- nmea_reader_init(p->reader);
- }
- }
|