Expand description
NMEA 0183 sentences to and from the KINAVIS types.
Anti-corruption layer between receiver sentences ($GPRMC,...*hh) and the
domain:
- Framing: length, printable characters, start character and a
mandatory checksum. Any failure is an
NmeaError. - Decoding into typed records —
Rmc,Gga,Gll,Vtg— whose fields are kernel types (Position,Speed,TrueCourse); out-of-domain values (latitude 95°) and implausible ones (see Plausibility bounds) are rejected here. AIS arrives asVdmwith the payload still armoured; decoding it is the AIS crate’s job. - Translation into a
GnssFixviaTryFrom<Rmc>orGga::fix_on.
Every step works on the input in place: no copies, no allocation, no panics. The crate builds for bare-metal targets without an allocator; CI checks the strict-profile build for panic paths.
encode and Display write a record back with its checksum, for
generating sentences and for round-trip tests.
use kinavis_nmea0183::{parse, Sentence};
use kinavis_kernel::GnssFix;
let line = b"$GPRMC,225444.00,A,4916.4500,N,12311.1200,W,3.0,272.5,110926,5.0,W,D*30\r\n";
let Sentence::Rmc(rmc) = parse(line)? else { panic!("not an RMC") };
let fix = GnssFix::try_from(rmc)?;
assert_eq!(format!("{}", fix.taken_at()), "2026-09-11T22:54:44.000 UTC");
assert_eq!(format!("{:.2}", fix.position()), "49°16.45'N 123°11.12'W");
assert_eq!(fix.speed_over_ground().map(|s| s.knots()), Some(3.0));
assert!(fix.quality().fix_type().is_position_fix());
// And back out again, checksum recomputed.
assert_eq!(format!("{rmc}"), "$GPRMC,225444.00,A,4916.4500,N,12311.1200,W,3.0,272.5,110926,5.0,W,D*30");§Plausibility bounds
A value outside these inclusive bounds is a corrupt field, not a
measurement, and fails with NmeaError::Value:
| Field | Bounds |
|---|---|
| Speed over ground | 0 to 1000 kn; 0 to 1852 km/h |
| Altitude (GGA) | −10 000 m to 100 000 m |
| Geoid separation (GGA) | −1000 m to 1000 m |
| Dilution of precision | 0 to 100; 0 reads as not available |
| Magnetic variation (RMC) | 180° either way; 999 and above read as not available |
| Differential age (GGA) | 0 s to 9999 s |
parse accepts sentences up to MAX_ACCEPTED_BYTES, past the
standard’s MAX_SENTENCE_BYTES: receivers write longer ones.
encode refuses a sentence longer than MAX_SENTENCE_BYTES with
NmeaError::TooLong. RMC, GLL and VTG always fit; a VDM fits with at
most 62 payload characters; a GGA can exceed the limit only with several
fields near their bounds at once.
§Not supported
Other sentences (satellites in view, DOP breakdowns, proprietary) return
Sentence::Unsupported with their address and a verified checksum, for
counting or logging.
§Feature flags
std(default) — standard library maths in the kernel.libm— forno_stdtargets:--no-default-features --features libm.
Structs§
- Address
- Sentence address field; at most 10 characters (proprietary maximum).
- Date
- Date as carried by a sentence.
- Gga
- Fix data: position, time, quality, satellites, HDOP, altitude.
- Gll
- Geographic position: latitude, longitude, time.
- Payload
- Armoured payload of one fragment.
- Rmc
- Recommended minimum: position, velocity, time and date.
- Talker
- Two-letter talker identifier:
GPGPS,GNmulti-constellation,GLGLONASS, etc. - Time
OfDay - UTC time of day as carried by a sentence, at the talker’s resolution.
- Vdm
- AIS message or one fragment of it.
- Vtg
- Course and speed over the ground.
Enums§
- Channel
- AIS radio channel.
- Mode
- Mode indicator (NMEA 2.3+): how the position was obtained.
- Nmea
Error - Why a sentence could not be read or written.
- Sentence
- Parsed sentence, supported or not.
- Status
- Data status of a position sentence:
AorV. - Translation
Error - Why a well-formed sentence could not become a
GnssFix.
Constants§
- MAX_
ACCEPTED_ BYTES - Maximum sentence length
parseaccepts,$andCR LFincluded. - MAX_
FRAGMENTS - Maximum number of fragments per message.
- MAX_
PAYLOAD_ CHARS - Maximum payload characters per fragment.
- MAX_
SENTENCE_ BYTES - Maximum sentence length in the standard,
$andCR LFincluded.encodenever writes more.