nmeasis 26.4.1

A memory-safe NMEA 0183 parser with a C FFI
Documentation

nmeasis

nmeasis is safe, zero-copy, no_std compatible NMEA0183 protocol parser written in Rust meant for use in embedded and constrainted contexts. It also comes with a C FFI, allowing you to integrate with projects in other languages.

Features

  • Written entirely in #![deny(unsafe_code)] no_std Rust.
  • Fully complete C FFI, allowing for use in C (with a provided example).
  • No memory allocations at all.
  • NmeaNumber perserves the precision of provided, eliding floating point error.
  • Access to raw sentence fields alongside parsed fields.
  • Parser is fuzzed on input, hardening against runtime panics.

Example

Rust

use nmeasis::parser::NmeaParser;

fn main() {
    let mut parser = NmeaParser::<256>::default();
    let input = b"$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76\r\n";
    let buf = parser.buffer();
    let n = input.len().min(buf.len());
    buf[..n].copy_from_slice(&input[..n]);
    parser.commit(n, |result| match result {
        Ok(sentence) => println!("{sentence:?}"),
        Err(e) => eprintln!("error: {e}"),
    });
}

C

#include <stdio.h>
#include <stdlib.h>
#include "nmeasis.h"

static void on_sentence(const Sentence *sentence, void *userdata) {
    (void)userdata;

    if (nmea_sentence_message_kind(sentence) != MESSAGE_TYPE_GGA) return;

    const Gga *gga = nmea_sentence_gga(sentence);
    if (!gga || !nmea_gga_has_fix(gga)) return;

    NmeaCoordinates coords;
    NmeaNumber altitude;
    if (!nmea_gga_coordinates(gga, &coords)) return;
    if (!nmea_gga_altitude(gga, &altitude))  return;

    printf("lat=%.6f  lon=%.6f  alt=%.1fm\n",
        coords.latitude.degrees  + nmea_number_to_f64(coords.latitude.minutes)  / 60.0,
        coords.longitude.degrees + nmea_number_to_f64(coords.longitude.minutes) / 60.0,
        nmea_number_to_f64(altitude));
}

int main(void) {
    CNmeaParser *parser = malloc(nmea_parser_size());
    nmea_parser_init(parser);

    const char *input = "$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76\r\n";

    uint8_t *buf;
    size_t len;
    nmea_parser_buffer(parser, &buf, &len);

    size_t n = strlen(input) < len ? strlen(input) : len;
    memcpy(buf, input, n);
    nmea_parser_commit(parser, n, on_sentence, NULL);

    free(parser);
    return 0;
}

Sentences

  • AAM - Waypoint Arrival Alarm
  • GGA - Global Positioning System Fix Data
  • GLL - Geographic Position (Latitude/Longitude)
  • GNS - GNSS Fix Data
  • GSA - GPS Dilution of Precision and Active Satellites
  • GST - GPS Pseudorange Noise Statistics
  • GSV - Satellites in View
  • RMC - Recommended Minimum Navigation Information
  • TXT - Text Transmission
  • VTG - Track made good and Ground Speed
  • ZDA - Time & Date

NmeaTime/NmeaDate/NmeaDateTime/NmeaDateTimeOffset

All of these are our internal representations of dates and times that were parsed from the protocol. They are provided as is but can be converted to friendlier formats if you are using the library from Rust.

All of these have a TryFrom implementation to their analog from the time if you enable the time feature.

All of these have a TryFrom implementation to their analog from the chrono if you enable the chrono feature.

NmeaNumber

This is our internal representation of floating point number that was parsed. This preserves all of the precision and is provided as is.

This has From implementations to f32 and f64 if you enable the float feature. This is also provided in the C FFI under nmea_number_to_f32 and nmea_number_to_f64.

NmeaCoordinates

This is our internal representation of the coordinates provided by the protocol. This mostly just wraps the NmeaNumber with some convenience for parsing.

This has a From implementation for a variety of types from the geo_types crate if you enable the geo feature.

Contributing

Contributions are welcome. Feel free to add any of the missing NMEA sentences.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.