| Crates.io | rustedbytes-nmea |
| lib.rs | rustedbytes-nmea |
| version | 0.1.0 |
| created_at | 2025-10-09 02:48:21.707666+00 |
| updated_at | 2025-10-09 02:48:21.707666+00 |
| description | Rust no_std library for parsing NMEA messages from a GNSS receiver |
| homepage | |
| repository | https://github.com/mad4j/rustedbytes-nmea |
| max_upload_size | |
| id | 1874892 |
| size | 1,916,095 |
Rust no_std library for parsing NMEA messages from a GNSS receiver.
no_std compatible - can be used in embedded systemsAdd this to your Cargo.toml:
[dependencies]
rustedbytes-nmea = "0.1.0"
use rustedbytes_nmea::{NmeaParser, MessageType, NmeaMessage, ParseError};
fn main() {
let parser = NmeaParser::new();
// NMEA sentence as bytes (can contain multiple messages or partial data)
let data = b"$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n";
// Parse the data
let result = parser.parse_bytes(data);
match result {
Ok((Some(message), bytes_consumed)) => {
// Successfully parsed a complete message
match message {
NmeaMessage::GGA(gga_data) => {
println!("GGA message from {:?}", gga_data.talker_id);
println!("Time: {}", gga_data.time());
println!("Latitude: {} {}", gga_data.latitude, gga_data.lat_direction);
println!("Longitude: {} {}", gga_data.longitude, gga_data.lon_direction);
println!("Altitude: {:?} {:?}", gga_data.altitude, gga_data.altitude_units);
println!("Satellites: {:?}", gga_data.num_satellites);
}
NmeaMessage::RMC(rmc_data) => {
println!("RMC message from {:?}", rmc_data.talker_id);
println!("Time: {}", rmc_data.time());
println!("Status: {}", rmc_data.status);
println!("Speed: {} knots", rmc_data.speed_knots);
}
_ => {} // Handle other message types
}
println!("Consumed {} bytes", bytes_consumed);
}
Ok((None, bytes_consumed)) => {
// Partial message or spurious data - need more bytes
println!("Partial message, consumed {} bytes", bytes_consumed);
}
Err((ParseError::InvalidMessage, bytes_consumed)) => {
// Complete but invalid message (e.g., missing mandatory fields)
println!("Invalid message found, consumed {} bytes", bytes_consumed);
}
Err((ParseError::InvalidChecksum, bytes_consumed)) => {
// Checksum verification failed
println!("Invalid checksum, consumed {} bytes", bytes_consumed);
}
}
}
use rustedbytes_nmea::{NmeaParser, MessageType};
fn main() {
let parser = NmeaParser::new();
// Simulate a stream of multiple NMEA sentences
let mut data = b"$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n\
$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A\r\n\
$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n".as_slice();
// Parse all messages in the stream
while !data.is_empty() {
match parser.parse_bytes(data) {
Ok((msg, consumed)) => {
if consumed == 0 {
// Partial message - would need more data in a real stream
break;
}
match msg {
Some(message) => {
println!("Parsed {:?} message", message.message_type());
}
None => {
// Spurious data consumed
println!("Consumed {} bytes of spurious data", consumed);
}
}
// Move to next message
data = &data[consumed..];
}
Err((error, consumed)) => {
println!("Parse error: {:?}, consumed {} bytes", error, consumed);
// Move past the invalid message
data = &data[consumed..];
}
}
}
}
The library automatically tracks which GNSS constellation provided each message through the talker_id field:
use rustedbytes_nmea::{NmeaParser, TalkerId};
fn main() {
let parser = NmeaParser::new();
// Parse messages from different constellations
let sentences = [
b"$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n", // GPS
b"$GLGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n", // GLONASS
b"$GAGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n", // Galileo
b"$GNGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n", // Multi-GNSS
];
for sentence in &sentences {
if let Ok((Some(message), _)) = parser.parse_bytes(sentence) {
if let Some(gga_data) = message.as_gga() {
match gga_data.talker_id {
TalkerId::GP => println!("GPS fix: {}", gga_data.time()),
TalkerId::GL => println!("GLONASS fix: {}", gga_data.time()),
TalkerId::GA => println!("Galileo fix: {}", gga_data.time()),
TalkerId::GN => println!("Multi-GNSS fix: {}", gga_data.time()),
_ => println!("Other constellation fix"),
}
}
}
}
}
| Talker ID | Constellation | Description |
|---|---|---|
GP |
GPS | Global Positioning System (USA) |
GL |
GLONASS | Russian satellite navigation |
GA |
Galileo | European satellite navigation |
GB |
BeiDou | Chinese satellite navigation (GBxxxx format) |
BD |
BeiDou | Chinese satellite navigation (BDxxxx format) |
GN |
Multi-GNSS | Combined data from multiple systems |
QZ |
QZSS | Japanese Quasi-Zenith Satellite System |
NmeaParserThe main parser structure. The parser is now stateless - it maintains no internal buffers or message storage.
new() - Create a new parser instanceparse_bytes(data: &[u8]) -> Result<(Option<NmeaMessage>, usize), (ParseError, usize)> - Parse bytes and return:
Ok((Some(message), bytes_consumed)) - Successfully parsed a complete, valid messageOk((None, bytes_consumed)) - Partial message (need more data) or consumed spurious charactersErr((ParseError::InvalidMessage, bytes_consumed)) - Complete message but missing mandatory fieldsErr((ParseError::InvalidChecksum, bytes_consumed)) - Checksum verification failedParseErrorError types returned when parsing fails:
InvalidMessage - Message is syntactically complete but missing mandatory fields or invalidInvalidChecksum - Checksum verification failed (not yet fully implemented)NmeaMessageEnum representing a parsed NMEA message with associated data.
GGA(GgaData) - Global Positioning System Fix DataRMC(RmcData) - Recommended Minimum Navigation InformationGSA(GsaData) - GPS DOP and active satellitesGSV(GsvData) - GPS Satellites in viewGLL(GllData) - Geographic Position - Latitude/LongitudeVTG(VtgData) - Track Made Good and Ground SpeedGNS(GnsData) - GNSS Fix Datamessage_type() -> MessageType - Get the message type identifiertalker_id() -> TalkerId - Get the talker ID (constellation identifier)as_gga() -> Option<&GgaData> - Extract GGA message parametersas_rmc() -> Option<&RmcData> - Extract RMC message parametersas_gsa() -> Option<&GsaData> - Extract GSA message parametersas_gsv() -> Option<&GsvData> - Extract GSV message parametersas_gll() -> Option<&GllData> - Extract GLL message parametersas_vtg() -> Option<&VtgData> - Extract VTG message parametersas_gns() -> Option<&GnsData> - Extract GNS message parametersMessageTypeEnumeration of NMEA message type identifiers:
GGA - Global Positioning System Fix DataRMC - Recommended Minimum Navigation InformationGSA - GPS DOP and active satellitesGSV - GPS Satellites in viewGLL - Geographic Position - Latitude/LongitudeVTG - Track Made Good and Ground SpeedGNS - GNSS Fix DataUnknown - Unrecognized message typeThe library provides typed parameter structures for each NMEA message type, allowing structured access to message-specific fields.
GgaDataGlobal Positioning System Fix Data parameters:
time() - Mandatory - UTC time (hhmmss format) - accessed via methodlatitude - Mandatory - Latitude valuelat_direction - Mandatory - N or Slongitude - Mandatory - Longitude valuelon_direction - Mandatory - E or Wfix_quality - Mandatory - Fix quality (0=invalid, 1=GPS fix, 2=DGPS fix, etc.)num_satellites - Optional - Number of satellites in usehdop - Optional - Horizontal Dilution of Precisionaltitude - Optional - Altitude above mean sea levelaltitude_units - Optional - Units of altitude (M for meters)geoid_separation - Optional - Height of geoid above WGS84 ellipsoidgeoid_units - Optional - Units of geoid separationage_of_diff - Optional - Age of differential GPS datadiff_station_id() - Optional - Differential reference station ID - accessed via methodNote: If any mandatory field is missing or cannot be parsed, the parser returns None.
RmcDataRecommended Minimum Navigation Information parameters:
time() - Mandatory - UTC time (hhmmss format) - accessed via methodstatus - Mandatory - Status (A=active/valid, V=void/invalid)latitude - Mandatory - Latitude valuelat_direction - Mandatory - N or Slongitude - Mandatory - Longitude valuelon_direction - Mandatory - E or Wspeed_knots - Mandatory - Speed over ground in knotstrack_angle - Mandatory - Track angle in degreesdate() - Mandatory - Date (ddmmyy format) - accessed via methodmagnetic_variation - Optional - Magnetic variationmag_var_direction - Optional - E or WNote: If any mandatory field is missing or cannot be parsed, the parser returns None.
GsaDataGPS DOP and active satellites parameters:
mode - Mandatory - Mode (M=manual, A=automatic)fix_type - Mandatory - Fix type (1=no fix, 2=2D, 3=3D)satellite_ids - Optional - Array of up to 12 satellite PRN numberspdop - Optional - Position Dilution of Precisionhdop - Optional - Horizontal Dilution of Precisionvdop - Optional - Vertical Dilution of PrecisionNote: If any mandatory field is missing or cannot be parsed, as_gsa() returns None.
GsvDataGPS Satellites in view parameters:
num_messages - Mandatory - Total number of GSV messagesmessage_num - Mandatory - Current message numbersatellites_in_view - Mandatory - Total number of satellites in viewsatellite_info - Optional - Array of up to 4 satellite information structuresEach SatelliteInfo contains:
prn - Optional - Satellite PRN numberelevation - Optional - Elevation in degrees (0-90)azimuth - Optional - Azimuth in degrees (0-359)snr - Optional - Signal-to-Noise Ratio in dBNote: If any mandatory field is missing or cannot be parsed, as_gsv() returns None.
GllDataGeographic Position parameters:
latitude - Mandatory - Latitude valuelat_direction - Mandatory - N or Slongitude - Mandatory - Longitude valuelon_direction - Mandatory - E or Wtime() - Mandatory - UTC time (hhmmss format) - accessed via methodstatus - Mandatory - Status (A=active/valid, V=void/invalid)Note: If any mandatory field is missing or cannot be parsed, the parser returns None.
VtgDataTrack Made Good and Ground Speed parameters (all fields are optional):
track_true - Optional - True track angletrack_true_indicator - Optional - T (true)track_magnetic - Optional - Magnetic track angletrack_magnetic_indicator - Optional - M (magnetic)speed_knots - Optional - Speed in knotsspeed_knots_indicator - Optional - N (knots)speed_kph - Optional - Speed in kilometers per hourspeed_kph_indicator - Optional - K (km/h)Note: VTG messages can be parsed even with all fields empty, as all fields are optional.
GnsDataGNSS Fix Data parameters:
time() - Mandatory - UTC time (hhmmss format) - accessed via methodlatitude - Mandatory - Latitude valuelat_direction - Mandatory - N or Slongitude - Mandatory - Longitude valuelon_direction - Mandatory - E or Wmode_indicator() - Mandatory - Position fix mode for each GNSS system - accessed via methodnum_satellites - Mandatory - Number of satellites in usehdop - Optional - Horizontal Dilution of Precisionaltitude - Optional - Altitude above mean sea levelgeoid_separation - Optional - Height of geoid above WGS84 ellipsoidage_of_diff - Optional - Age of differential GPS datadiff_station_id() - Optional - Differential reference station ID - accessed via methodnav_status - Optional - Navigation status indicatorNote: If any mandatory field is missing or cannot be parsed, the parser returns None.
For detailed information about the library's compliance with the NMEA 0183 standard, including supported and unsupported message types and fields, see the NMEA 0183 Compliance Matrix.
Run the test suite:
cargo test
Contributions are welcome! Please ensure:
cargo test)cargo fmt)cargo clippy)For maintainers: See RELEASE.md for instructions on creating a new release.
MIT License - see LICENSE file for details.