/** * Parses a message. If the message could not be parsed, NULL is returned. The * return value be cast to the proper struct, based on the determined message * type. * * If the message could not be parsed, and if the outError pointer is non-NULL, * its contents will be set to the appropriate error code. */ LIBNMEA_PUBLIC nmea_message_t *nmea_parse_message(char *message, nmea_error_t *outError) { assert(message != NULL); // If we can parse the message, point to it here nmea_message_t *parsed; // Create a copy of the input message. int len = strlen(message); char *copy = malloc(len + 2); strncpy(copy, message, len + 2); // Figure out what function will parse this message nmea_message_type_t t = nmea_get_message_type(message); switch(t) { case kNMEAMessageGGA: parsed = (nmea_message_t *) parse_gga(copy, outError); break; case kNMEAMessageGSA: parsed = (nmea_message_t *) parse_gsa(copy, outError); break; case kNMEAMessageGSV: parsed = (nmea_message_t *) parse_gsv(copy, outError); break; case kNMEAMessageVTG: parsed = (nmea_message_t *) parse_vtg(copy, outError); break; // The message was of an unknown type. (Handles kNMEAMessageUnknown) default: if(outError) *outError = kNMEAErrorTypeNotUnderstood; parsed = NULL; break; } // Ensure we don't pass back invalid data. assert(parsed); // Clean up free(copy); parsed->type = t; // We're done. return parsed; }
int main(int argc, char* argv[]) { FILE* file; int arg_index; char* buf = 0; const unsigned int bufsize = 256; const char* tokens[32]; const int len = sizeof tokens / sizeof tokens[0]; int token_count; struct GGA* gga; struct GNS* gns; struct GSA* gsa; struct RMC* rmc; buf = malloc(bufsize); if (!buf) { goto exit; } for (arg_index=1; arg_index<argc; ++arg_index) { file = fopen(argv[arg_index], "r"); if (!file) { continue; } while (fgets(buf, bufsize, file)) { if (strlen(buf) < 10) continue; if (!verify_checksum(buf)) break; fprintf(stdout, "%s", buf); token_count = tokenize(buf, tokens, len); if (0 !=(gga = parse_gga(tokens, token_count))) { fprintf(stdout, " GGA %02d:%02d:%02d %.6f , %.6f %d, %d, %.2f, %.1f(%s), %.1f(%s) \n", gga->hour, gga->min, gga->sec, gga->lat, gga->lon, gga->quality, gga->sat_count, gga->hdop, gga->altitude, tokens[10], gga->geoid_height, tokens[12]); free(gga); } else if (0 != (gns = parse_gns(tokens, token_count))) { fprintf(stdout, " GNS %02d:%02d:%02d %.6f , %.6f %s, %d, %.2f, %.1f(%s), %.1f(%s) \n", gns->hour, gns->min, gns->sec, gns->lat, gns->lon, gns->mode, gns->sat_count, gns->hdop, gns->altitude, "m", gns->geoid_height, "m"); free(gns); } else if (0 != (gsa = parse_gsa(tokens, token_count))) { int i; int prn; fprintf(stdout, " GSA %c, %d, ", gsa->mode, gsa->fix_type); i = 0; while (i<12 && 0 != (prn = gsa->prn[i])) { fprintf(stdout,"%d, ", prn); ++i; } fprintf(stdout, "%.1f, %.1f, %.1f\n", gsa->pdop, gsa->hdop, gsa->vdop); free(gsa); } else if (0 != (rmc = parse_rmc(tokens, token_count))) { fprintf(stdout, " RMC %02d:%02d:%02d %.6f , %.6f %.1f(knots), %.1f(degrees) %02d-%02d-%02d\n", rmc->hour, rmc->min, rmc->sec, rmc->lat, rmc->lon, rmc->speed, rmc->heading, rmc->day, rmc->month, rmc->year); free(rmc); } } // while fclose(file); } exit: if (buf) { free(buf); } return 0; }
bool put_nmea_msg(struct nmea_parser_t *ctx, const uint8_t *msg, size_t msg_size, struct gps_msg_status_t *status) { unsigned i; char msg_id[9]; assert(msg_size > 1 && msg_size <= NMEA_MAX); assert((size_t)looks_like_nmea(msg, msg_size) == msg_size); status->is_valid = false; status->location_changed = false; status->err[0] = '\0'; ctx->stats->rcvd.nmea.last_msg_ts = ctx->stats->rcvd.last_byte_ts; ctx->stats->rcvd.nmea.total += 1; for (i=0; i < sizeof(msg_id); ++i) { if (i >= msg_size) { msg_id[i] = '\0'; break; }else { if (msg[i] == ',') { msg_id[i] = '\0'; break; }else { msg_id[i] = (char)msg[i]; } } } msg_id[sizeof(msg_id)-1] = '\0'; if ( (strcmp("$GPGGA", msg_id) == 0) || (strcmp("$GNGGA", msg_id) == 0) || (strcmp("$GLGGA", msg_id) == 0) || (strcmp("$GAGGA", msg_id) == 0) ) { struct nmea_gpgga_t gxgga; if (parse_gga(msg, msg_size, &gxgga, status)) { if (!is_same_fix_time(ctx->fix.fix_time, gxgga.fix_time)) { close_nmea_fix(ctx, status); open_nmea_fix(&ctx->fix, gxgga.fix_time); } ctx->fix.gpgga_active = true; ctx->fix.gpgga = gxgga; ctx->stats->rcvd.nmea.gga += 1; } }else if ( (strcmp("$GPRMC", msg_id) == 0) || (strcmp("$GNRMC", msg_id) == 0) || (strcmp("$GLRMC", msg_id) == 0) || (strcmp("$GARMC", msg_id) == 0) ) { struct nmea_gprmc_t gxrmc; if (parse_rmc(msg, msg_size, &gxrmc, status)) { if (!is_same_fix_time(ctx->fix.fix_time, gxrmc.fix_time)) { close_nmea_fix(ctx, status); open_nmea_fix(&ctx->fix, gxrmc.fix_time); } ctx->fix.gprmc_active = true; ctx->fix.gprmc = gxrmc; ctx->stats->rcvd.nmea.rmc += 1; } }else if (strcmp("$GPGLL", msg_id) == 0) { struct nmea_gpgll_t gxgll; if (parse_gll(msg, msg_size, &gxgll, status)) { if (!is_same_fix_time(ctx->fix.fix_time, gxgll.fix_time)) { close_nmea_fix(ctx, status); open_nmea_fix(&ctx->fix, gxgll.fix_time); } ctx->fix.gpgll_active = true; ctx->fix.gpgll = gxgll; ctx->stats->rcvd.nmea.gll += 1; } }else if (strcmp("$GPGST", msg_id) == 0) { struct nmea_gpgst_t gpgst; if (parse_gst(msg, msg_size, &gpgst, status)) { if (!is_same_fix_time(ctx->fix.fix_time, gpgst.fix_time)) { close_nmea_fix(ctx, status); open_nmea_fix(&ctx->fix, gpgst.fix_time); } ctx->fix.gpgst_active = true; ctx->fix.gpgst = gpgst; ctx->stats->rcvd.nmea.gst += 1; } }else if (strcmp("$GPGSA", msg_id) == 0) { struct nmea_gpgsa_t gpgsa; if (parse_gsa(msg, msg_size, &gpgsa, status)) { gpgsa.is_valid = true; ctx->gpgsa = gpgsa; ctx->stats->rcvd.nmea.gsa += 1; } }else if (strcmp("$GPVTG", msg_id) == 0) { struct nmea_gpvtg_t gpvtg; if (parse_vtg(msg, msg_size, &gpvtg, status)) { gpvtg.is_valid = true; ctx->gpvtg = gpvtg; ctx->stats->rcvd.nmea.vtg += 1; } }else if (strcmp("$GPZDA", msg_id) == 0) { struct nmea_gpzda_t gpzda; if (parse_zda(msg, msg_size, &gpzda, status)) { ctx->fix.gpzda_active = true; ctx->fix.gpzda = gpzda; ctx->stats->rcvd.nmea.zda += 1; } }else if (strcmp("$GPGSV", msg_id) == 0) { // TODO status->is_valid = true; ctx->stats->rcvd.nmea.gsv += 1; }else if (strcmp("$PUBX", msg_id) == 0) { // TODO status->is_valid = true; ctx->stats->rcvd.nmea.pubx += 1; } else { set_nmea_error(status, msg, msg_size, "unk msg"); status->is_valid = true; ctx->stats->rcvd.nmea.other += 1; } return status->is_valid; }