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

#![no_std]
#![forbid(unsafe_code)]
//use message::{Message, MessageBuilder};
//use preamble::MessageFrame;
use crc_any;
#[cfg(feature = "serde")]
use sd::{de::Visitor, Deserialize, Serialize};
use tinyvec;

#[cfg(feature = "test_gen")]
mod source_repr;
#[cfg(feature = "test_gen")]
pub mod val_gen;

mod df;
pub mod msg;
pub mod rtcm_error;
pub mod util;

pub use msg::message::{Message, MessageBuilder};

mod message_frame;
pub use message_frame::MessageFrame;

pub mod prelude {
    pub use crate::rtcm_error::RtcmError;
    #[cfg(feature = "test_gen")]
    pub use crate::source_repr::{SourceOutput, SourceRepr};
    pub use crate::{next_msg_frame, Message, MessageBuilder, MessageFrame, MsgFrameIter};
}

/// 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.
///
/// # Parameters
///
/// * `data` - A `&[u8]` to search for a `MessageFrame`
///
/// # Returns
///
/// A tuple containing the number of bytes consumed, and a `MessageFrame` if one was found.
pub fn next_msg_frame(data: &[u8]) -> (usize, Option<MessageFrame>) {
    for (i, b) in data.iter().enumerate() {
        if *b == 0xd3 {
            match MessageFrame::new(&data[i..]) {
                Ok(m) => return (i + m.frame_len(), Some(m)),
                Err(rtcm_error::RtcmError::Incomplete) => return (i, None),
                Err(rtcm_error::RtcmError::NotValid) => {
                    continue;
                }
                _ => unreachable!(),
            }
        }
    }
    (data.len(), None)
}

/// MsgFrameIter is an iterator that returns `MessageFrame`s found in a `&[u8]`.
pub struct MsgFrameIter<'a> {
    data: &'a [u8],
    index: usize,
}
impl<'a> MsgFrameIter<'a> {
    /// Creates a new MsgFrameIter from a `&[u8]`
    ///
    /// # Parameters
    ///
    /// * `data` - A `&[u8]` to search for `MessageFrame`s
    pub fn new(data: &'a [u8]) -> Self {
        MsgFrameIter { data, index: 0 }
    }
    /// Returns the number of bytes consumed by the iterator so far
    pub fn consumed(&self) -> usize {
        self.index
    }
}
impl<'a> core::iter::Iterator for &mut MsgFrameIter<'a> {
    type Item = MessageFrame<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.data.len() {
            return None;
        }
        let (consumed, mf) = next_msg_frame(&self.data[self.index..]);
        self.index += consumed;
        mf
    }
}