Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ categories = ["embedded", "no-std", "parser-implementations"]
readme = "README.md"

[dependencies]
defmt = { version = "1", optional = true }
heapless = { version = "0.9", optional = true }

[features]
default = ["strict"]
mtk = []
txt = ["dep:heapless"]
strict = []
defmt = ["dep:defmt"]

[badges]
codecov = { repository = "nsforth/nmea0183" }
Expand Down
23 changes: 15 additions & 8 deletions src/coords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
use core::convert::TryFrom;

/// Earth hemisphere
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Hemisphere {
/// North
North,
Expand All @@ -15,7 +16,8 @@ pub enum Hemisphere {
}

/// Latitude as reported by receiver.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Latitude {
/// Degrees
pub degrees: u8,
Expand Down Expand Up @@ -121,7 +123,8 @@ impl Latitude {
}

/// Longitude as reported by receiver.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Longitude {
/// Degrees
pub degrees: u8,
Expand Down Expand Up @@ -227,7 +230,8 @@ impl Longitude {
}

/// Altitude reported by receiver typically in GGA sentence.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Altitude {
/// Altitude in meters over ground.
pub meters: f32,
Expand All @@ -248,7 +252,8 @@ impl Altitude {
}

/// Speed reported by receiver typically in RMC and VTG sentences.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Speed {
knots: f32,
}
Expand Down Expand Up @@ -305,7 +310,8 @@ impl Speed {
}

/// The course over ground.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Course {
/// Course in degrees from North rotated clockwise.
pub degrees: f32,
Expand All @@ -331,10 +337,11 @@ impl Course {
}

/// The course over ground calculated from True course and magnetic variation.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MagneticCourse {
/// Course in degrees from Magnetic North Pole rotated clockwise.
degrees: f32,
pub degrees: f32,
}

impl From<f32> for MagneticCourse {
Expand Down
9 changes: 6 additions & 3 deletions src/datetime.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! NMEA date and time structures.
/// NMEA date
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Date {
/// NMEA day
pub day: u8,
Expand Down Expand Up @@ -47,7 +48,8 @@ impl Date {
}

/// NMEA time in UTC
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Time {
/// Hours as reported by receiver
pub hours: u8,
Expand Down Expand Up @@ -100,7 +102,8 @@ impl Time {
}

/// NMEA date and time in UTC
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DateTime {
/// NMEA date
pub date: Date,
Expand Down
6 changes: 4 additions & 2 deletions src/gga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::Source;
use core::time::Duration;

/// Geographic coordinates including altitude, GPS solution quality, DGPS usage information.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GGA {
/// Navigational system.
pub source: Source,
Expand Down Expand Up @@ -78,7 +79,8 @@ impl GGA {
}

/// Quality of GPS solution
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum GPSQuality {
/// No solution
NoFix,
Expand Down
3 changes: 2 additions & 1 deletion src/gll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::modes::{Mode, Status};
use crate::Source;

/// Geographic latitude ang longitude sentence with time of fix and receiver state.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GLL {
/// Navigational system.
pub source: Source,
Expand Down
6 changes: 4 additions & 2 deletions src/gsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::Source;
const MAX_PRNS_PER_MESSAGE: usize = 12;

/// GPS DOP and active satellites
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GSA {
/// Navigational system.
pub source: Source,
Expand Down Expand Up @@ -65,7 +66,8 @@ impl GSA {
}

/// Receiver mode of positioning.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FixType {
/// No valid position is available.
NoFix,
Expand Down
3 changes: 2 additions & 1 deletion src/gsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::satellite::Satellite;
use crate::Source;
const MAX_SATELLITES_PER_MESSAGE: usize = 4;
/// Satellites in views including the number of SVs in view, the PRN numbers, elevations, azimuths, and SNR values.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GSV {
/// Navigational system.
pub source: Source,
Expand Down
49 changes: 43 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub(crate) mod mtk;
pub(crate) mod rmc;
pub(crate) mod vtg;
pub(crate) mod zda;
#[cfg(feature = "txt")]
pub(crate) mod txt;

pub use gga::GPSQuality;
pub use gga::GGA;
Expand All @@ -113,9 +115,12 @@ pub use mtk::PMTKSPF;
pub use rmc::RMC;
pub use vtg::VTG;
pub use zda::ZDA;
#[cfg(feature = "txt")]
pub use txt::{TXT, MessageType};

/// Source of NMEA sentence like GPS, GLONASS or other.
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Source {
/// USA Global Positioning System
GPS = 0b1,
Expand All @@ -127,12 +132,16 @@ pub enum Source {
Beidou = 0b1000,
/// Global Navigation Sattelite System. Some combination of other systems. Depends on receiver model, receiver settings, etc..
GNSS = 0b10000,
/// Quasi-Zenith Satellite System
QZSS = 0b100000,
#[cfg(feature = "mtk")]
/// MediaTek NMEA packet protocol
MTK = 0b100000,
MTK = 0b1000000,
}

/// Mask for Source filter in Parser.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SourceMask {
mask: u32,
}
Expand Down Expand Up @@ -179,15 +188,21 @@ impl TryFrom<&str> for Source {
"GA" => Ok(Source::Gallileo),
"BD" => Ok(Source::Beidou),
"GN" => Ok(Source::GNSS),
"GQ" => Ok(Source::QZSS),
#[cfg(feature = "mtk")]
"PM" => Ok(Source::MTK),
_ => Err("Source is not supported!"),
source => {
#[cfg(feature = "defmt")]
defmt::error!("Source is not supported: {}", source);
Err("Source is not supported!")
}
}
}
}

/// Various kinds of NMEA sentence like RMC, VTG or other. Used for filter by sentence type in Parser.
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Sentence {
/// Recommended minimum sentence.
RMC = 0b1,
Expand All @@ -206,6 +221,9 @@ pub enum Sentence {
GSA = 0b1000000,
/// Current Date and Time.
ZDA = 0b10000000,
#[cfg(feature = "txt")]
/// Text message from receiver.
TXT = 0b100000000,
}

impl TryFrom<&str> for Sentence {
Expand All @@ -222,13 +240,21 @@ impl TryFrom<&str> for Sentence {
"PMTK" => Ok(Sentence::PMTK),
"GSA" => Ok(Sentence::GSA),
"ZDA" => Ok(Sentence::ZDA),
#[cfg(feature = "txt")]
"TXT" => Ok(Sentence::TXT),

_ => Err("Unsupported sentence type."),
sentence => {
#[cfg(feature = "defmt")]
defmt::error!("Unsupported NMEA sentence type: {}", sentence);
Err("Unsupported sentence type.")
}
}
}
}

/// Mask for Sentence filter in Parser.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SentenceMask {
mask: u32,
}
Expand Down Expand Up @@ -269,6 +295,7 @@ impl BitOr<Sentence> for SentenceMask {
/// Sentences with many null fields or sentences without valid data is also parsed and returned as None.
/// None ParseResult may be interpreted as working receiver but without valid data.
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ParseResult {
/// The Recommended Minimum Sentence for any GNSS. Typically most used.
RMC(Option<RMC>),
Expand All @@ -287,6 +314,9 @@ pub enum ParseResult {
GSA(Option<GSA>),
/// Current Date and Time.
ZDA(Option<ZDA>),
#[cfg(feature = "txt")]
/// Text message from receiver.
TXT(Option<TXT>),
}

#[cfg(feature = "strict")]
Expand All @@ -299,6 +329,8 @@ pub const MAX_SENTENCE_LENGTH: usize = 120usize;

/// Parses NMEA sentences and stores intermediate parsing state.
/// Parser is tolerant for errors so you should not reinitialize it after errors.
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Parser {
buffer: [u8; MAX_SENTENCE_LENGTH],
buflen: usize,
Expand All @@ -309,7 +341,8 @@ pub struct Parser {
sentence_mask: SentenceMask,
}

#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum ParserState {
WaitStart,
ReadUntilChkSum,
Expand All @@ -319,6 +352,8 @@ enum ParserState {
WaitLF,
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
struct ParserIterator<'a> {
parser: &'a mut Parser,
input: Iter<'a, u8>,
Expand Down Expand Up @@ -472,6 +507,8 @@ impl Parser {
Sentence::GSV => Ok(Some(ParseResult::GSV(GSV::parse(source, &mut iter)?))),
Sentence::GSA => Ok(Some(ParseResult::GSA(GSA::parse(source, &mut iter)?))),
Sentence::ZDA => Ok(Some(ParseResult::ZDA(ZDA::parse(source, &mut iter)?))),
#[cfg(feature = "txt")]
Sentence::TXT => Ok(Some(ParseResult::TXT(TXT::parse(source, &mut iter)?))),

#[cfg(feature = "mtk")]
Sentence::PMTK => {
Expand Down
6 changes: 4 additions & 2 deletions src/modes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) enum Status {
Valid,
NotValid,
Expand All @@ -15,7 +16,8 @@ impl Status {
}

/// Receiver mode of operation.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Mode {
/// Autonomous mode without any external correction.
Autonomous,
Expand Down
9 changes: 6 additions & 3 deletions src/mtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::Source;
use core::convert::TryFrom;

/// MTK NMEA packet type
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MTKPacketType {
/// Related to Spoofing and Jamming detection
SPF,
Expand All @@ -20,7 +21,8 @@ impl TryFrom<&str> for MTKPacketType {
}

/// Related to Spoofing and Jamming detection .
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PMTKSPF {
/// Navigational system.
pub source: Source,
Expand All @@ -46,7 +48,8 @@ impl PMTKSPF {
}

/// Status of gps Jamming
#[derive(Debug, PartialEq, Clone,Copy)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum JammingStatus {
/// No Jamming
Healthy,
Expand Down
3 changes: 2 additions & 1 deletion src/rmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::modes::{Mode, Status};
use crate::Source;

/// Recommended Minimum Sentence for any GNSS source.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RMC {
/// Navigational system.
pub source: Source,
Expand Down
3 changes: 2 additions & 1 deletion src/satellite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
use crate::common;

///Information about satellite in view.
#[derive(Debug, PartialEq, Clone, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Satellite {
/// Satellite pseudo-random noise number.
pub prn: u16,
Expand Down
Loading