/** * 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; }
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; }