uf_crsf/
parser.rs

1use crate::{
2    constants,
3    error::CrsfStreamError,
4    packets::{Packet, PacketAddress},
5};
6use crc::Crc;
7use num_enum::TryFromPrimitive;
8
9#[derive(Debug, Default, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub enum State {
12    #[default]
13    AwaitingSync,
14    AwaitingLenth,
15    Reading(usize),
16    AwaitingCrc,
17}
18
19#[derive(Debug)]
20pub struct CrsfParser {
21    buffer: [u8; constants::CRSF_MAX_PACKET_SIZE],
22    state: State,
23    position: usize,
24}
25
26const CRC8_DVB_S2: Crc<u8> = Crc::<u8>::new(&crc::CRC_8_DVB_S2);
27
28impl CrsfParser {
29    pub fn new() -> Self {
30        Self {
31            buffer: [0; constants::CRSF_MAX_PACKET_SIZE],
32            state: State::AwaitingSync,
33            position: 0,
34        }
35    }
36
37    pub fn push_byte_raw(
38        &mut self,
39        byte: u8,
40    ) -> Result<Option<RawCrsfPacket<'_>>, CrsfStreamError> {
41        match self.state {
42            State::AwaitingSync => {
43                if PacketAddress::try_from_primitive(byte).is_ok() {
44                    self.position = 0;
45                    self.buffer[self.position] = byte;
46                    self.state = State::AwaitingLenth;
47                    Ok(None)
48                } else {
49                    self.state = State::AwaitingSync;
50                    Err(CrsfStreamError::InvalidSync(byte))
51                }
52            }
53            State::AwaitingLenth => {
54                let n = byte as usize + 2;
55
56                if !(constants::CRSF_MIN_PACKET_SIZE..constants::CRSF_MAX_PACKET_SIZE).contains(&n)
57                {
58                    self.reset();
59                    return Err(CrsfStreamError::InvalidPacketLength(byte));
60                }
61                self.position = 1;
62                self.buffer[self.position] = byte;
63                self.state = State::Reading(n - 1);
64                Ok(None)
65            }
66            State::Reading(n) => {
67                self.position += 1;
68                self.buffer[self.position] = byte;
69                if self.position == n - 1 {
70                    self.state = State::AwaitingCrc;
71                }
72                Ok(None)
73            }
74            State::AwaitingCrc => {
75                self.position += 1;
76                self.buffer[self.position] = byte;
77
78                let mut digest = CRC8_DVB_S2.digest();
79                digest.update(&self.buffer[2..self.position]);
80                let calculated_crc = digest.finalize();
81                let packet_crc = self.buffer[self.position];
82
83                if calculated_crc != packet_crc {
84                    self.reset();
85                    return Err(CrsfStreamError::InvalidCrc {
86                        calculated_crc,
87                        packet_crc,
88                    });
89                }
90                let start = 0;
91                let end = self.position + 1;
92                self.reset();
93                let bytes = &self.buffer[start..end];
94                match RawCrsfPacket::new(bytes) {
95                    None => Err(CrsfStreamError::InputBufferTooSmall),
96                    Some(packet) => Ok(Some(packet)),
97                }
98            }
99        }
100    }
101
102    pub fn iter_packets<'a, 'b>(&'a mut self, buffer: &'b [u8]) -> PacketIterator<'a, 'b> {
103        PacketIterator {
104            parser: self,
105            buffer,
106            pos: 0,
107        }
108    }
109
110    pub fn push_byte(&mut self, byte: u8) -> Result<Option<Packet>, CrsfStreamError> {
111        match self.push_byte_raw(byte) {
112            Ok(Some(raw_packet)) => match Packet::parse(&raw_packet) {
113                Ok(packet) => Ok(Some(packet)),
114                Err(e) => Err(CrsfStreamError::ParsingError(e)),
115            },
116            Ok(None) => Ok(None),
117            Err(e) => Err(e),
118        }
119    }
120
121    pub fn reset(&mut self) {
122        self.position = 0;
123        self.state = State::AwaitingSync;
124    }
125}
126
127impl Default for CrsfParser {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133/// Represents a valid, but unparsed, CRSF packet.
134///
135/// This struct is a zero-copy view into a byte buffer that has been validated
136/// to contain a complete CRSF packet, including the sync byte, length, type,
137/// payload, and CRC. It provides methods to access the different parts of the
138/// packet without parsing the payload itself.
139#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
140#[cfg_attr(feature = "defmt", derive(defmt::Format))]
141pub struct RawCrsfPacket<'a> {
142    bytes: &'a [u8],
143}
144
145impl<'a> RawCrsfPacket<'a> {
146    /// Creates a new `RawCrsfPacket` from a byte slice.
147    ///
148    /// Returns `None` if the slice is shorter than the minimum possible
149    /// CRSF packet length (4 bytes).
150    pub fn new(bytes: &'a [u8]) -> Option<Self> {
151        if bytes.len() >= 4 {
152            Some(Self { bytes })
153        } else {
154            None
155        }
156    }
157
158    /// Returns the destination address byte of the packet.
159    pub fn dst_addr(&self) -> u8 {
160        self.bytes[0]
161    }
162
163    /// Returns the raw packet type byte.
164    pub fn raw_packet_type(&self) -> u8 {
165        self.bytes[2]
166    }
167
168    /// Returns a slice representing the packet's payload.
169    ///
170    /// The payload does not include the CRSF framing (destination, size, type, CRC).
171    pub fn payload(&self) -> &[u8] {
172        &self.bytes[3..self.bytes.len() - 1]
173    }
174
175    /// Returns the CRC check byte of the packet.
176    #[expect(clippy::missing_panics_doc, reason = "infallible")]
177    pub fn crc(&self) -> u8 {
178        *self.bytes.last().expect("infallible due to length check")
179    }
180
181    /// Returns the total length of the packet in bytes, including the framing.
182    pub fn len(&self) -> usize {
183        self.bytes.len()
184    }
185
186    /// Returns `true` if the packet has a length of zero.
187    ///
188    /// Note: A valid CRSF packet should not be empty.
189    pub fn is_empty(&self) -> bool {
190        self.bytes.is_empty()
191    }
192}
193
194pub struct PacketIterator<'a, 'b> {
195    parser: &'a mut CrsfParser,
196    buffer: &'b [u8],
197    pos: usize,
198}
199
200impl Iterator for PacketIterator<'_, '_> {
201    type Item = Result<Packet, CrsfStreamError>;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        while self.pos < self.buffer.len() {
205            let byte = self.buffer[self.pos];
206            self.pos += 1;
207
208            match self.parser.push_byte(byte) {
209                Ok(Some(packet)) => return Some(Ok(packet)),
210                Ok(None) => (),
211                Err(err) => return Some(Err(err)),
212            }
213        }
214        None
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    extern crate std;
221
222    use super::*;
223    use crate::packets::{
224        write_packet_to_buffer, CrsfPacket, LinkStatistics, PacketAddress, PacketType,
225        RcChannelsPacked,
226    };
227
228    #[test]
229    fn test_construction() {
230        let raw_bytes: [u8; 14] = [0xC8, 12, 0x14, 16, 19, 99, 151, 1, 2, 3, 8, 88, 148, 252];
231        let mut parser = CrsfParser::new();
232
233        for b in &raw_bytes[0..raw_bytes.len() - 1] {
234            let result = parser.push_byte_raw(*b);
235            assert!(matches!(result, Ok(None)));
236        }
237
238        let raw_packet_result = parser.push_byte_raw(raw_bytes[13]);
239        let raw_packet = raw_packet_result
240            .expect("Failed to get raw packet result")
241            .expect("Expected a complete raw packet, but got None");
242
243        assert_eq!(raw_packet.len(), raw_bytes.len());
244
245        assert_eq!(raw_packet.payload().len(), LinkStatistics::MIN_PAYLOAD_SIZE);
246        assert_eq!(
247            raw_packet.raw_packet_type(),
248            PacketType::LinkStatistics as u8
249        );
250
251        let data = &raw_packet.payload();
252        let ls = LinkStatistics::from_bytes(data).unwrap();
253        let p = Packet::parse(&raw_packet).unwrap();
254        assert_eq!(Packet::LinkStatistics(ls.clone()), p);
255
256        assert_eq!(ls.uplink_rssi_1, 16);
257    }
258
259    #[test]
260    fn test_parsing() {
261        let raw_bytes: [u8; 40] = [
262            0xC8, 12, 0x14, 16, 19, 99, 151, 1, 2, 3, 8, 88, 148, 252, 0xC8, 24, 0x16, 0xE0, 0x03,
263            0x1F, 0x58, 0xC0, 0x07, 0x16, 0xB0, 0x80, 0x05, 0x2C, 0x60, 0x01, 0x0B, 0xF8, 0xC0,
264            0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 103,
265        ];
266        let mut parser = CrsfParser::new();
267        let results: std::vec::Vec<Result<Packet, CrsfStreamError>> =
268            parser.iter_packets(&raw_bytes).collect();
269
270        let expected = [
271            992, 992, 352, 992, 352, 352, 352, 352, 352, 352, 992, 992, 0, 0, 0, 0,
272        ];
273        assert_eq!(results.len(), 2);
274
275        assert!(results[0].is_ok());
276        assert!(results[1].is_ok());
277        assert_eq!(
278            Packet::RCChannels(RcChannelsPacked(expected)),
279            results[1].clone().ok().unwrap()
280        );
281    }
282
283    #[test]
284    fn test_raw_to_full_packet_conversion() {
285        let link_stats_packet = LinkStatistics {
286            uplink_rssi_1: 16,
287            uplink_rssi_2: 19,
288            uplink_link_quality: 99,
289            uplink_snr: 51 as i8,
290            active_antenna: 1,
291            rf_mode: 2,
292            uplink_tx_power: 3,
293            downlink_rssi: 8,
294            downlink_link_quality: 88,
295            downlink_snr: 48 as i8,
296        };
297
298        // Serialize it into a buffer
299        let mut buffer = [0u8; 64];
300        let bytes_written = write_packet_to_buffer(
301            &mut buffer,
302            PacketAddress::FlightController,
303            &link_stats_packet,
304        )
305        .unwrap();
306        let raw_bytes = &buffer[..bytes_written];
307
308        let mut parser = CrsfParser::new();
309
310        // 1. Parse raw bytes to get a RawCrsfPacket
311        let mut raw_packet_result = Ok(None);
312        for &byte in raw_bytes {
313            raw_packet_result = parser.push_byte_raw(byte);
314            if let Ok(Some(_)) = &raw_packet_result {
315                break;
316            }
317        }
318        let raw_packet = raw_packet_result
319            .expect("Failed to get raw packet result")
320            .expect("Expected a complete raw packet, but got None");
321
322        let packet = Packet::parse(&raw_packet).expect("Failed to parse raw packet into a Packet");
323
324        // Verify the resulting packet
325        assert!(matches!(packet, Packet::LinkStatistics(_)));
326        if let Packet::LinkStatistics(stats) = packet {
327            assert_eq!(stats, link_stats_packet)
328        }
329    }
330}