Giter Site home page Giter Site logo

nmea-parser's Introduction

NMEA Parser for Rust

NMEA Parser on crates.io NMEA Parser on docs.rs GitHub last commit

This Rust crate aims to cover all AIS sentences and the most important GNSS sentences used with NMEA 0183 standard. It supports both AIS class A and class B.

Usage

Include the following fragment in your Cargo.toml file:

[dependencies]
nmea-parser = "0.11.0"

The following example code fragment uses the crate to parse the given NMEA sentences and to print some parsed fields. It relies on unwrap() function to simplify the example. In real-life applications proper handling of None cases is needed.

use nmea_parser::*;

// Create parser and define sample sentences
let mut parser = NmeaParser::new();
let sentences = vec![
  "!AIVDM,1,1,,A,H42O55i18tMET00000000000000,2*6D",
  "!AIVDM,1,1,,A,H42O55lti4hhhilD3nink000?050,0*40",
  "$GAGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*56",
];

// Parse the sentences and print some fields of the messages
for sentence in sentences {    
    match parser.parse_sentence(sentence)? {
        ParsedMessage::VesselDynamicData(vdd) => {
            println!("MMSI:    {}",        vdd.mmsi);
            println!("Speed:   {:.1} kts", vdd.sog_knots.unwrap());
            println!("Heading: {}°",       vdd.heading_true.unwrap());
            println!("");
        },
        ParsedMessage::VesselStaticData(vsd) => {
            println!("MMSI:  {}", vsd.mmsi);
            println!("Flag:  {}", vsd.country().unwrap());
            println!("Name:  {}", vsd.name.unwrap());
            println!("Type:  {}", vsd.ship_type);
            println!("");
        },
        ParsedMessage::Gga(gga) => {
            println!("Source:    {}",     gga.source);
            println!("Latitude:  {:.3}°", gga.latitude.unwrap());
            println!("Longitude: {:.3}°", gga.longitude.unwrap());
            println!("");
        },
        ParsedMessage::Rmc(rmc) => {
            println!("Source:  {}",        rmc.source);
            println!("Speed:   {:.1} kts", rmc.sog_knots.unwrap());
            println!("Bearing: {}°",       rmc.bearing.unwrap());
            println!("Time:    {}",        rmc.timestamp.unwrap());
            println!("");
        },
        _ => {
        }
    }
}

The example outputs the following lines:

MMSI:  271041815
Flag:  TR
Name:  PROGUY
Type:  passenger

Source:    Galileo
Latitude:  48.117°
Longitude: 11.517°

Features

The following features are included in the published version of the crate. Details about version history can be found from the changelog.

Feature Description
AIS sentences VDM/VDO types 1-5, 9-27
GNSS sentences ALM, DBS, DPT, DTM, GGA, GLL, GNS, GSA, GSV, HDT, MTW, MWV, RMC, VTG, MSS, STN, VBW, VHW, ZDA
Satellite systems GPS, GLONASS, Galileo, BeiDou, NavIC and QZSS

Roadmap

The following table outlines the high-level changes that are going to be included in the future versions. Prioritization is based on estimated significance and implementation effort of each item. Until version 1.0 refactoring and renaming of code elements is likely to happen.

Version Category Content
0.12 AIS VDM/VDO types 6-8
1.0 general Stable API, optimizations, documentation enhancements, even more unit tests, examples
1.1 GNSS AAM, BOD, BWC, R00, RMB, ROT, RTE, WPL, ZTG, APB, GBS, RMA, GRS, GST, MSK, STN, VBW, XTE, XTR

License

This crate is licensed under Apache 2.0 license which also includes the liability and warranty statements.

nmea-parser's People

Contributors

arne91 avatar blueluna avatar brandonros avatar jtojnar avatar linuseing avatar martinfrances107 avatar richardeoin avatar surban avatar tiphaineruy avatar wezm avatar zaari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nmea-parser's Issues

Thoughts on rustfmt

I notice that the code isn't formatted with rustfmt, the official Rust code formatter. I was wondering if you'd be open to a PR that formatted the code with it? The benefit in my eyes is that you can just let the tool take care of it, knowing that it will be consistent with other code in the Rust ecosystem. I notice that in some places you've formatted code a particular way (tables of bits for example). If I were to format the project I'd try to make sure that things like this were preserved.

error[E0635]: unknown feature `stdsimd`

error[E0635]: unknown feature `stdsimd`
  --> /home/drebbe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ahash-0.7.6/src/lib.rs:33:42
   |
33 | #![cfg_attr(feature = "stdsimd", feature(stdsimd))]
   |                                          ^^^^^^^

For more information about this error, try `rustc --explain E0635`.

rust-lang/hashbrown#499

Hashbrown crate needs to have support for ahash 0.8.7 or newer.

$ cargo tree -i ahash -p nmea-parser
ahash v0.7.6
└── hashbrown v0.12.3
    └── nmea-parser v0.10.0

Other NMEA Sentences

Hey, do you plan on including other nmea sentences like DPT and DBT?
I would offer to implement them.

Panic when parsing AIS messages

Code panics when parsing messages with invalid payload:
ex: Type26
!AIVDM,1,1,,,Jl@bhbmCU`:lwOd0,0*48

( I'm using this Lib to parse huge files, thus I need to avoid panic and correctly propagate errors)

But this isn't the only type it can panic on. All messages with valid decode but with invalid payload length will panic because of the way byteslices are extracted:

BitVec::from_bitslice(...
Which panics.

Although this message is invalid, valid information can be extracted from it:
If you paste it here: http://ais.tbsalling.dk/ you get everything up to the data.

Proposals:

  • I could just pr fixes on each message for which I get a panic and go from there...
  • Quick fix: add test on length when parsing ( wrapp all ::from_bitslice with a length check and throw error on invalid length )
  • Refactor with a parsing lib such as https://github.com/Geal/nom

I could spend some time working on that but I guess it really depend on the status of the lib.
How do you this this lib future ? Have any plan for it ?

Extending parser with proprietary sentences

I need to interact with a proprietary GPS logger that sends sentences like:

$PMTK182,8,0001F800,FFFFFFFFFFFFFF…FFFFF*52

Now I could wrap the parse_sentence function and handle those proprietary functions in the wrapper but I would have to duplicate code like checksum verification.

Possible solutions:

  • Include the whole sentence as a struct field in ParseError::UnsupportedSentenceType so that wrapper can attempt to handle it after running parse_sentence.
  • Return Ok(ParsedMessage::Proprietary(String)) from parse_sentence instead of ParseError::UnsupportedSentenceType.
  • Factor out the verify_and_strip_checksum function and make it public.
  • Add NmeaParserFull<ProprietaryMessagesType> (NmeaParser would become NmeaParserFull<()>) and a method like NmeaParserFull::register_parser_for_prefix<H>(prefix: &str, handler: H) where H: Fn(&str) -> Option<ProprietaryMessagesType>

Cannot access underlying data

Issue:
When parsing an AIS frame. you sometime might want to access the raw data.

example:
VesselDynamicData.nav_status is an enum constructed from an u8 field. If you need to use the parser as an intermediate parser for other tool, you might want to use the underlying u8 and not manipulate the enum

solutions:

  • for fields store the raw value in the object and only parse the enum when requested.
  • do not store the raw value and impl "to_value" for enums and accept dataloss for enums mapping different values to one enum field -> ex: ShipType ' 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 => ShipType::HighSpeedCraft,'

Panic when parsing message

Hi, thanks for creating this library!

I encounter panic when trying to parse certain messages, an example of the issue is included as follows

use nmea_parser::NmeaParser;

fn parsemsg(sentence: &str) {
    let mut parser = NmeaParser::new();

    if let Ok(payload) = parser.parse_sentence(sentence) {
        println!("did not panic yet {:?}", payload);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn this_works() {
        let sentence = "!AIVDM,1,1,,,19NS8eP01t2rTJugUtmqOoVL00R@,0*53";
        parsemsg(sentence);
        let sentence2 = "!AIVDM,not,a,valid,nmea,string,0*00";
        parsemsg(sentence2);
    }

    #[test]
    fn this_panics() {
        let sentence = "!AIVDM,1,1,,,;ie05s`0Kk6UvFiQ`IaUfW3iC8pB,0*02";
        parsemsg(sentence);
    }
}

Produces output

running 2 tests
test errcheck::tests::this_works ... ok
test errcheck::tests::this_panics ... FAILED

failures:

---- errcheck::tests::this_panics stdout ----
thread 'errcheck::tests::this_panics' panicked at 'No such local time', /home/matt/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.19/src/offset/mod.rs:173:34
stack backtrace:
   0: std::panicking::begin_panic
             at /rustc/1.57.0/library/std/src/panicking.rs:543:12
   1: chrono::offset::LocalResult<T>::unwrap
             at /home/matt/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.19/src/offset/mod.rs:173:34
   2: chrono::offset::TimeZone::ymd
             at /home/matt/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.19/src/offset/mod.rs:214:9
   3: nmea_parser::ais::vdm_t11::handle
             at /home/matt/.cargo/registry/src/github.com-1ecc6299db9ec823/nmea-parser-0.8.0/src/ais/vdm_t11.rs:31:17
   4: nmea_parser::NmeaParser::parse_sentence
             at /home/matt/.cargo/registry/src/github.com-1ecc6299db9ec823/nmea-parser-0.8.0/src/lib.rs:577:31
   5: rust_aisdb_lib::errcheck::parsemsg
             at ./src/errcheck.rs:6:26
   6: rust_aisdb_lib::errcheck::tests::this_panics
             at ./src/errcheck.rs:26:9
   7: rust_aisdb_lib::errcheck::tests::this_panics::{{closure}}
             at ./src/errcheck.rs:24:5
   8: core::ops::function::FnOnce::call_once
             at /rustc/1.57.0/library/core/src/ops/function.rs:227:5
   9: core::ops::function::FnOnce::call_once
             at /rustc/1.57.0/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    errcheck::tests::this_panics

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.06s

error: test failed, to rerun pass '--lib'

Parsed UTC timestamps using local date instead of GPS date

I have a receiver that sends multiple messages with GPS/UTC time. When parsing the timestamp field returns the correct h/m/s, but not the correct date in most cases. (Appends the local computer date) This is most apparent when testing on a machine where the actual date is not the same as the real GPS/UTC date.

The RMC message does parse and return the correct date in the timestamp while the GLL and GGA messages ignore the date. The NMEA string appears to have the same UTC format, but the message parsers here use different utility functions. There may be additional instances in messages I'm not receiving.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.