1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub const FRAGMENT_LEN: usize = 180;
6pub const MAX_FRAGMENTS: usize = 4;
8pub const MAX_MESSAGE_LEN: usize = FRAGMENT_LEN * MAX_FRAGMENTS;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Fragment {
14 pub flags: u8,
17 pub len: u8,
19 pub data: [u8; FRAGMENT_LEN],
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct TooLong(
26 pub usize,
28);
29
30impl std::fmt::Display for TooLong {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(
33 f,
34 "RTCM message of {} bytes exceeds {} bytes",
35 self.0, MAX_MESSAGE_LEN
36 )
37 }
38}
39
40impl std::error::Error for TooLong {}
41
42pub fn message_fragments(len: usize) -> Result<usize, TooLong> {
45 if len > MAX_MESSAGE_LEN {
46 Err(TooLong(len))
47 } else if len <= FRAGMENT_LEN {
48 Ok(1)
49 } else if len.is_multiple_of(FRAGMENT_LEN) && len < MAX_MESSAGE_LEN {
50 Ok(len / FRAGMENT_LEN + 1)
52 } else {
53 Ok(len.div_ceil(FRAGMENT_LEN))
54 }
55}
56
57#[derive(Debug, Default, Clone)]
60pub struct Fragmenter {
61 seq: u8,
62}
63
64impl Fragmenter {
65 pub fn fragment(&mut self, msg: &[u8]) -> Result<Vec<Fragment>, TooLong> {
68 let count = message_fragments(msg.len())?;
69 if msg.len() <= FRAGMENT_LEN {
70 let mut data = [0u8; FRAGMENT_LEN];
71 data[..msg.len()].copy_from_slice(msg);
72 return Ok(vec![Fragment {
73 flags: 0,
74 len: msg.len() as u8,
75 data,
76 }]);
77 }
78 let seq = self.seq & 0x1f;
79 self.seq = (self.seq + 1) & 0x1f;
80 Ok((0..count)
81 .map(|id| {
82 let start = (id * FRAGMENT_LEN).min(msg.len());
83 let chunk = &msg[start..(start + FRAGMENT_LEN).min(msg.len())];
84 let mut data = [0u8; FRAGMENT_LEN];
85 data[..chunk.len()].copy_from_slice(chunk);
86 Fragment {
87 flags: 1 | ((id as u8 & 0x3) << 1) | (seq << 3),
88 len: chunk.len() as u8,
89 data,
90 }
91 })
92 .collect())
93 }
94}
95
96pub fn fragment_count(bytes: &[u8]) -> Result<usize, TooLong> {
99 split_rtcm3(bytes)
100 .into_iter()
101 .map(|m| message_fragments(m.len()))
102 .sum()
103}
104
105const PREAMBLE: u8 = 0xD3;
107
108pub fn crc24q(bytes: &[u8]) -> u32 {
110 let mut crc: u32 = 0;
111 for &b in bytes {
112 crc ^= (b as u32) << 16;
113 for _ in 0..8 {
114 crc <<= 1;
115 if crc & 0x0100_0000 != 0 {
116 crc ^= 0x0186_4CFB;
117 }
118 }
119 }
120 crc & 0x00FF_FFFF
121}
122
123pub fn encode_rtcm3(payload: &[u8]) -> Vec<u8> {
126 let len = payload.len().min(0x3FF);
127 let mut v = Vec::with_capacity(len + 6);
128 v.extend([PREAMBLE, (len >> 8) as u8 & 0x03, len as u8]);
129 v.extend_from_slice(&payload[..len]);
130 let crc = crc24q(&v);
131 v.extend(&crc.to_be_bytes()[1..]);
132 v
133}
134
135fn scan(bytes: &[u8], mut frame: impl FnMut(std::ops::Range<usize>)) -> usize {
144 let mut tail: Option<usize> = None;
145 let mut i = 0;
146 while i < bytes.len() {
147 if bytes[i] != PREAMBLE {
148 i += 1;
149 continue;
150 }
151 if i + 3 > bytes.len() {
152 tail.get_or_insert(i);
153 break;
154 }
155 let len = (((bytes[i + 1] & 0x03) as usize) << 8) | bytes[i + 2] as usize;
156 let body_end = i + 3 + len;
157 let end = body_end + 3;
158 if end > bytes.len() {
159 tail.get_or_insert(i);
160 i += 1;
161 continue;
162 }
163 let want =
164 u32::from_be_bytes([0, bytes[body_end], bytes[body_end + 1], bytes[body_end + 2]]);
165 if crc24q(&bytes[i..body_end]) == want {
166 tail = None;
169 frame(i..end);
170 i = end;
171 } else {
172 i += 1;
173 }
174 }
175 tail.unwrap_or(bytes.len())
176}
177
178pub fn split_rtcm3(bytes: &[u8]) -> Vec<&[u8]> {
182 let mut out = Vec::new();
183 scan(bytes, |r| out.push(&bytes[r]));
184 out
185}
186
187#[derive(Debug, Default, Clone)]
192pub struct Rtcm3Splitter {
193 buf: Vec<u8>,
194}
195
196impl Rtcm3Splitter {
197 pub fn push(&mut self, bytes: &[u8]) -> Vec<Vec<u8>> {
199 self.buf.extend_from_slice(bytes);
200 let mut out = Vec::new();
201 let buf = &self.buf;
202 let tail = scan(buf, |r| out.push(buf[r].to_vec()));
203 self.buf.drain(..tail);
204 out
205 }
206
207 pub fn pending(&self) -> usize {
209 self.buf.len()
210 }
211}
212
213#[cfg(test)]
214mod tests;