rtcm_rs/
lib.rs

1//! # rtcm-rs
2//!
3//! `rtcm-rs` is a Rust library for decoding and encoding RTCM version 3 messages as defined in the RTCM Standard 10403.x.
4//! This library aims to provide an efficient, safe, and easy-to-use way to handle RTCM messages. Currently, the library
5//! supports a subset of the RTCM standard's messages, but we're working to extend the support to all messages.
6//!
7//! This library uses `#[forbid(unsafe_code)]` attribute, ensuring that all operations are safe from undefined behavior,
8//! data races, and many common bugs. Therefore, you can rely on `rtcm-rs` for not only its functionality but also its commitment to safety.
9//!
10//! The library also provides support for `serde`, a powerful serialization and deserialization framework, allowing users to convert RTCM
11//! messages into various formats such as JSON, XML and more. Furthermore, `rtcm-rs` is `no_std` compatible and doesn't rely
12//! on dynamic memory allocations, which makes it suitable for use in embedded systems.
13//!
14//! Here are some examples of how you can use `rtcm-rs`:
15//!
16//! ## Decoding a RTCM message
17//! ```no_run
18//! use rtcm_rs::prelude::*;
19//! use std::io::Read;
20//!
21//! # fn main() {
22//! let mut rtcm_file = std::fs::File::open("testdata/msg1001_3.rtcm").unwrap();
23//! let mut buffer = Vec::<u8>::new();
24//! rtcm_file.read_to_end(&mut buffer).unwrap();
25//!
26//! if let (_, Some(message_frame)) = next_msg_frame(buffer.as_slice()) {
27//!     let msg = message_frame.get_message();
28//!     println!("{:?}", msg);
29//! }
30//! # }
31//! ```
32//!
33//! ## Encoding a RTCM message
34//! ```no_run
35//! use rtcm_rs::prelude::*;
36//! use rtcm_rs::msg::{Msg1001T, Msg1001Sat};
37//! use rtcm_rs::util::DataVec;
38//!
39//! # fn main() {
40//! let mut message_builder = MessageBuilder::new();
41//!
42//! let result = message_builder.build_message(
43//!     &Message::Msg1001(
44//!         Msg1001T {
45//!             reference_station_id: 100,
46//!             gps_epoch_time_ms: 0,
47//!             synchronous_gnss_msg_flag: 0,
48//!             divergence_free_smoothing_flag: 0,
49//!             smoothing_interval_index: 0,
50//!             satellites: {
51//!                 let mut satellites = DataVec::new();
52//!                 satellites.push(Msg1001Sat {
53//!                     gps_satellite_id: 20,
54//!                     gps_l1_code_ind: 0,
55//!                     l1_pseudorange_m: Some(20000000.0),
56//!                     l1_phase_pseudorange_diff_m: Some(0.2),
57//!                     l1_lock_time_index: 0,
58//!                 });
59//!                 satellites.push(Msg1001Sat {
60//!                     gps_satellite_id: 21,
61//!                     gps_l1_code_ind: 0,
62//!                     l1_pseudorange_m: Some(26000000.0),
63//!                     l1_phase_pseudorange_diff_m: Some(0.4),
64//!                     l1_lock_time_index: 0,
65//!                 });
66//!                 satellites
67//!             }}));
68//!
69//! if let Ok(bytes) = result {
70//!     println!("Encoded message: {:?}", bytes);
71//! }
72//! # }
73//! ```
74//!
75//! For a full list of features and capabilities, see the [README](https://github.com/martinhakansson/rtcm-rs/blob/master/README.md).
76
77// #![no_std]
78#![cfg_attr(not(feature = "std"), no_std)]
79#![forbid(unsafe_code)]
80//use message::{Message, MessageBuilder};
81//use preamble::MessageFrame;
82use crc_any;
83#[cfg(feature = "serde")]
84use sd::{de::Visitor, Deserialize, Serialize};
85use tinyvec;
86
87#[cfg(feature = "test_gen")]
88mod source_repr;
89#[cfg(feature = "test_gen")]
90pub mod val_gen;
91
92mod df;
93pub mod msg;
94pub mod rtcm_error;
95pub mod util;
96
97pub use msg::message::{Message, MessageBuilder};
98
99mod message_frame;
100pub use message_frame::MessageFrame;
101
102pub mod prelude {
103    pub use crate::rtcm_error::RtcmError;
104    #[cfg(feature = "test_gen")]
105    pub use crate::source_repr::{SourceOutput, SourceRepr};
106    pub use crate::{next_msg_frame, Message, MessageBuilder, MessageFrame, MsgFrameIter};
107}
108
109/// next_msg_frame takes a slice of bytes and returns a tuple containing the number of bytes consumed, and a `MessageFrame` if one was found.
110///
111/// # Parameters
112///
113/// * `data` - A `&[u8]` to search for a `MessageFrame`
114///
115/// # Returns
116///
117/// A tuple containing the number of bytes consumed, and a `MessageFrame` if one was found.
118pub fn next_msg_frame(data: &[u8]) -> (usize, Option<MessageFrame>) {
119    for (i, b) in data.iter().enumerate() {
120        if *b == 0xd3 {
121            match MessageFrame::new(&data[i..]) {
122                Ok(m) => return (i + m.frame_len(), Some(m)),
123                Err(rtcm_error::RtcmError::Incomplete) => return (i, None),
124                Err(rtcm_error::RtcmError::NotValid) => {
125                    continue;
126                }
127                _ => unreachable!(),
128            }
129        }
130    }
131    (data.len(), None)
132}
133
134/// MsgFrameIter is an iterator that returns `MessageFrame`s found in a `&[u8]`.
135pub struct MsgFrameIter<'a> {
136    data: &'a [u8],
137    index: usize,
138}
139impl<'a> MsgFrameIter<'a> {
140    /// Creates a new MsgFrameIter from a `&[u8]`
141    ///
142    /// # Parameters
143    ///
144    /// * `data` - A `&[u8]` to search for `MessageFrame`s
145    pub fn new(data: &'a [u8]) -> Self {
146        MsgFrameIter { data, index: 0 }
147    }
148    /// Returns the number of bytes consumed by the iterator so far
149    pub fn consumed(&self) -> usize {
150        self.index
151    }
152}
153impl<'a> core::iter::Iterator for &mut MsgFrameIter<'a> {
154    type Item = MessageFrame<'a>;
155
156    fn next(&mut self) -> Option<Self::Item> {
157        if self.index >= self.data.len() {
158            return None;
159        }
160        let (consumed, mf) = next_msg_frame(&self.data[self.index..]);
161        self.index += consumed;
162        mf
163    }
164}