cu_msp_lib/
lib.rs

1pub mod commands;
2pub mod structs;
3
4use crc_any::CRCu8;
5use packed_struct::PackedStruct;
6use smallvec::SmallVec;
7use std::error::Error;
8use std::fmt::{Debug, Display, Formatter};
9use std::{fmt, mem};
10
11#[derive(Clone, PartialEq)]
12pub struct MspPacketData(pub(crate) SmallVec<[u8; 256]>);
13
14impl MspPacketData {
15    pub(crate) fn new() -> MspPacketData {
16        MspPacketData(SmallVec::new())
17    }
18
19    pub fn as_mut_slice(&mut self) -> &mut [u8] {
20        let MspPacketData(data) = self;
21        data.as_mut_slice()
22    }
23}
24// By definition an MSP packet cannot be larger than 255 bytes
25
26impl Debug for MspPacketData {
27    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
28        let MspPacketData(data) = self;
29        if data.is_empty() {
30            write!(f, "empty")?;
31            return Ok(());
32        }
33        write!(f, "0x")?;
34        for byte in data {
35            write!(f, "{:02X}", byte)?;
36        }
37        Ok(())
38    }
39}
40
41impl From<&[u8]> for MspPacketData {
42    fn from(data: &[u8]) -> Self {
43        MspPacketData(SmallVec::from_slice(data))
44    }
45}
46
47impl MspPacketData {
48    pub fn as_slice(&self) -> &[u8] {
49        let Self(data) = self;
50        data
51    }
52}
53
54/// Packet parsing error
55#[derive(Copy, Clone, Debug, PartialEq)]
56pub enum MspPacketParseError {
57    OutputBufferSizeMismatch,
58    CrcMismatch { expected: u8, calculated: u8 },
59    InvalidData,
60    InvalidHeader1,
61    InvalidHeader2,
62    InvalidDirection,
63    InvalidDataLength,
64}
65
66impl Display for MspPacketParseError {
67    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
68        match self {
69            MspPacketParseError::OutputBufferSizeMismatch => {
70                write!(f, "Output buffer size mismatch")
71            }
72            MspPacketParseError::CrcMismatch {
73                expected,
74                calculated,
75            } => write!(
76                f,
77                "CRC mismatch, expected: 0x{:02X}, calculated: 0x{:02X}",
78                expected, calculated
79            ),
80            MspPacketParseError::InvalidData => write!(f, "Invalid data"),
81            MspPacketParseError::InvalidHeader1 => write!(f, "Invalid header 1"),
82            MspPacketParseError::InvalidHeader2 => write!(f, "Invalid header 2"),
83            MspPacketParseError::InvalidDirection => write!(f, "Invalid direction"),
84            MspPacketParseError::InvalidDataLength => write!(f, "Invalid data length"),
85        }
86    }
87}
88
89impl Error for MspPacketParseError {}
90
91/// Packet's desired destination
92#[derive(Copy, Clone, Debug, PartialEq)]
93pub enum MspPacketDirection {
94    /// Network byte '<'
95    ToFlightController,
96    /// Network byte '>'
97    FromFlightController,
98    /// Network byte '!'
99    Unsupported,
100}
101
102impl MspPacketDirection {
103    /// To network byte
104    pub fn to_byte(&self) -> u8 {
105        let b = match *self {
106            MspPacketDirection::ToFlightController => '<',
107            MspPacketDirection::FromFlightController => '>',
108            MspPacketDirection::Unsupported => '!',
109        };
110        b as u8
111    }
112}
113
114#[derive(Debug, Clone, PartialEq)]
115/// A decoded MSP packet, with a command code, direction and payload
116pub struct MspPacket {
117    pub cmd: u16,
118    pub direction: MspPacketDirection,
119    pub data: MspPacketData,
120}
121
122#[derive(Copy, Clone, PartialEq, Debug)]
123enum MspParserState {
124    Header1,
125    Header2,
126    Direction,
127    FlagV2,
128    DataLength,
129    DataLengthV2,
130    Command,
131    CommandV2,
132    Data,
133    DataV2,
134    Crc,
135}
136
137#[derive(Copy, Clone, PartialEq, Debug)]
138enum MspVersion {
139    V1,
140    V2,
141}
142
143#[derive(Debug)]
144/// Parser that can find packets from a raw byte stream
145pub struct MspParser {
146    state: MspParserState,
147    packet_version: MspVersion,
148    packet_direction: MspPacketDirection,
149    packet_cmd: u16,
150    packet_data_length_remaining: usize,
151    packet_data: MspPacketData,
152    packet_crc: u8,
153    packet_crc_v2: CRCu8,
154}
155
156impl MspParser {
157    /// Create a new parser
158    pub fn new() -> MspParser {
159        Self {
160            state: MspParserState::Header1,
161            packet_version: MspVersion::V1,
162            packet_direction: MspPacketDirection::ToFlightController,
163            packet_data_length_remaining: 0,
164            packet_cmd: 0,
165            packet_data: MspPacketData::new(),
166            packet_crc: 0,
167            packet_crc_v2: CRCu8::crc8dvb_s2(),
168        }
169    }
170
171    /// Are we waiting for the header of a brand new packet?
172    pub fn state_is_between_packets(&self) -> bool {
173        self.state == MspParserState::Header1
174    }
175
176    /// Parse the next input byte. Returns a valid packet whenever a full packet is received, otherwise
177    /// restarts the state of the parser.
178    pub fn parse(&mut self, input: u8) -> Result<Option<MspPacket>, MspPacketParseError> {
179        match self.state {
180            MspParserState::Header1 => {
181                if input == b'$' {
182                    self.state = MspParserState::Header2;
183                } else {
184                    self.reset();
185                }
186            }
187
188            MspParserState::Header2 => {
189                self.packet_version = match input as char {
190                    'M' => MspVersion::V1,
191                    'X' => MspVersion::V2,
192                    _ => {
193                        self.reset();
194                        return Err(MspPacketParseError::InvalidHeader2);
195                    }
196                };
197
198                self.state = MspParserState::Direction;
199            }
200
201            MspParserState::Direction => {
202                match input {
203                    60 => self.packet_direction = MspPacketDirection::ToFlightController, // '>'
204                    62 => self.packet_direction = MspPacketDirection::FromFlightController, // '<'
205                    33 => self.packet_direction = MspPacketDirection::Unsupported, // '!' error
206                    _ => {
207                        self.reset();
208                        return Err(MspPacketParseError::InvalidDirection);
209                    }
210                }
211
212                self.state = match self.packet_version {
213                    MspVersion::V1 => MspParserState::DataLength,
214                    MspVersion::V2 => MspParserState::FlagV2,
215                };
216            }
217
218            MspParserState::FlagV2 => {
219                // uint8, flag, usage to be defined (set to zero)
220                self.state = MspParserState::CommandV2;
221                self.packet_data = MspPacketData::new();
222                self.packet_crc_v2.digest(&[input]);
223            }
224
225            MspParserState::CommandV2 => {
226                let MspPacketData(data) = &mut self.packet_data;
227                data.push(input);
228
229                if data.len() == 2 {
230                    let mut s = [0u8; size_of::<u16>()];
231                    s.copy_from_slice(data);
232                    self.packet_cmd = u16::from_le_bytes(s);
233
234                    self.packet_crc_v2.digest(&data);
235                    data.clear();
236                    self.state = MspParserState::DataLengthV2;
237                }
238            }
239
240            MspParserState::DataLengthV2 => {
241                let MspPacketData(data) = &mut self.packet_data;
242                data.push(input);
243
244                if data.len() == 2 {
245                    let mut s = [0u8; size_of::<u16>()];
246                    s.copy_from_slice(data);
247                    self.packet_data_length_remaining = u16::from_le_bytes(s).into();
248                    self.packet_crc_v2.digest(data);
249                    data.clear();
250                    if self.packet_data_length_remaining == 0 {
251                        self.state = MspParserState::Crc;
252                    } else {
253                        self.state = MspParserState::DataV2;
254                    }
255                }
256            }
257
258            MspParserState::DataV2 => {
259                let MspPacketData(data) = &mut self.packet_data;
260                data.push(input);
261                self.packet_data_length_remaining -= 1;
262
263                if self.packet_data_length_remaining == 0 {
264                    self.state = MspParserState::Crc;
265                }
266            }
267
268            MspParserState::DataLength => {
269                let MspPacketData(data) = &mut self.packet_data;
270                self.packet_data_length_remaining = input as usize;
271                self.state = MspParserState::Command;
272                self.packet_crc ^= input;
273                data.clear();
274            }
275
276            MspParserState::Command => {
277                self.packet_cmd = input as u16;
278
279                if self.packet_data_length_remaining == 0 {
280                    self.state = MspParserState::Crc;
281                } else {
282                    self.state = MspParserState::Data;
283                }
284
285                self.packet_crc ^= input;
286            }
287
288            MspParserState::Data => {
289                let MspPacketData(data) = &mut self.packet_data;
290                data.push(input);
291                self.packet_data_length_remaining -= 1;
292
293                self.packet_crc ^= input;
294
295                if self.packet_data_length_remaining == 0 {
296                    self.state = MspParserState::Crc;
297                }
298            }
299
300            MspParserState::Crc => {
301                let MspPacketData(data) = &mut self.packet_data;
302                if self.packet_version == MspVersion::V2 {
303                    self.packet_crc_v2.digest(data);
304                    self.packet_crc = self.packet_crc_v2.get_crc();
305                }
306
307                let packet_crc = self.packet_crc;
308                if input != packet_crc {
309                    self.reset();
310                    return Err(MspPacketParseError::CrcMismatch {
311                        expected: input,
312                        calculated: packet_crc,
313                    });
314                }
315
316                let mut n = MspPacketData::new();
317                mem::swap(&mut self.packet_data, &mut n);
318
319                let packet = MspPacket {
320                    cmd: self.packet_cmd,
321                    direction: self.packet_direction,
322                    data: n,
323                };
324
325                self.reset();
326
327                return Ok(Some(packet));
328            }
329        }
330
331        Ok(None)
332    }
333
334    pub fn reset(&mut self) {
335        let MspPacketData(data) = &mut self.packet_data;
336        self.state = MspParserState::Header1;
337        self.packet_direction = MspPacketDirection::ToFlightController;
338        self.packet_data_length_remaining = 0;
339        self.packet_cmd = 0;
340        data.clear();
341        self.packet_crc = 0;
342        self.packet_crc_v2.reset();
343    }
344}
345
346impl Default for MspParser {
347    fn default() -> Self {
348        Self::new()
349    }
350}
351
352impl MspPacket {
353    /// Number of bytes that this packet requires to be packed
354    pub fn packet_size_bytes(&self) -> usize {
355        let MspPacketData(data) = &self.data;
356        6 + data.len()
357    }
358
359    /// Number of bytes that this packet requires to be packed
360    pub fn packet_size_bytes_v2(&self) -> usize {
361        let MspPacketData(data) = &self.data;
362        9 + data.len()
363    }
364
365    /// Serialize to network bytes
366    pub fn serialize(&self, output: &mut [u8]) -> Result<(), MspPacketParseError> {
367        let MspPacketData(data) = &self.data;
368        let l = output.len();
369
370        if l != self.packet_size_bytes() {
371            return Err(MspPacketParseError::OutputBufferSizeMismatch);
372        }
373
374        output[0] = b'$';
375        output[1] = b'M';
376        output[2] = self.direction.to_byte();
377        output[3] = data.len() as u8;
378        output[4] = self.cmd as u8;
379
380        output[5..l - 1].copy_from_slice(data);
381
382        let mut crc = output[3] ^ output[4];
383        for b in data {
384            crc ^= *b;
385        }
386        output[l - 1] = crc;
387
388        Ok(())
389    }
390
391    /// Serialize to network bytes
392    pub fn serialize_v2(&self, output: &mut [u8]) -> Result<(), MspPacketParseError> {
393        let MspPacketData(data) = &self.data;
394        let l = output.len();
395
396        if l != self.packet_size_bytes_v2() {
397            return Err(MspPacketParseError::OutputBufferSizeMismatch);
398        }
399
400        output[0] = b'$';
401        output[1] = b'X';
402        output[2] = self.direction.to_byte();
403        output[3] = 0;
404        output[4..6].copy_from_slice(&self.cmd.to_le_bytes());
405        output[6..8].copy_from_slice(&(data.len() as u16).to_le_bytes());
406
407        output[8..l - 1].copy_from_slice(data);
408
409        let mut crc = CRCu8::crc8dvb_s2();
410        crc.digest(&output[3..l - 1]);
411        output[l - 1] = crc.get_crc();
412
413        Ok(())
414    }
415
416    pub fn decode_as<T: PackedStruct>(&self) -> Result<T, packed_struct::PackingError> {
417        let expected_size = size_of::<T::ByteArray>();
418
419        if self.data.0.len() < expected_size {
420            return Err(packed_struct::PackingError::BufferSizeMismatch {
421                expected: expected_size,
422                actual: self.data.0.len(),
423            });
424        }
425
426        let byte_array: &T::ByteArray = unsafe { &*(self.data.0.as_ptr() as *const T::ByteArray) };
427
428        T::unpack(byte_array)
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use super::*;
435    use smallvec::smallvec;
436    #[test]
437    fn test_serialize() {
438        let packet = MspPacket {
439            cmd: 2,
440            direction: MspPacketDirection::ToFlightController,
441            data: MspPacketData(smallvec![0xbe, 0xef]),
442        };
443
444        let size = packet.packet_size_bytes();
445        assert_eq!(8, size);
446
447        let mut output = vec![0; size];
448        packet.serialize(&mut output).unwrap();
449        let expected = [b'$', b'M', b'<', 2, 2, 0xbe, 0xef, 81];
450        assert_eq!(&expected, output.as_slice());
451
452        let mut packet_parsed = None;
453        let mut parser = MspParser::new();
454        for b in output {
455            let s = parser.parse(b);
456            if let Ok(Some(p)) = s {
457                packet_parsed = Some(p);
458                break;
459            }
460        }
461
462        assert_eq!(packet, packet_parsed.unwrap());
463    }
464
465    #[test]
466    fn test_roundtrip() {
467        fn roundtrip(packet: &MspPacket) {
468            let size = packet.packet_size_bytes();
469            let mut output = vec![0; size];
470
471            packet.serialize(&mut output).unwrap();
472            let mut parser = MspParser::new();
473            let mut packet_parsed = None;
474            for b in output {
475                let s = parser.parse(b);
476                if let Ok(Some(p)) = s {
477                    packet_parsed = Some(p);
478                    break;
479                }
480            }
481            assert_eq!(packet, &packet_parsed.unwrap());
482        }
483
484        {
485            let packet = MspPacket {
486                cmd: 1,
487                direction: MspPacketDirection::ToFlightController,
488                data: MspPacketData(smallvec![0x00, 0x00, 0x00]),
489            };
490            roundtrip(&packet);
491        }
492
493        {
494            let packet = MspPacket {
495                cmd: 200,
496                direction: MspPacketDirection::FromFlightController,
497                data: MspPacketData::new(),
498            };
499            roundtrip(&packet);
500        }
501
502        {
503            let packet = MspPacket {
504                cmd: 100,
505                direction: MspPacketDirection::Unsupported,
506                data: MspPacketData(smallvec![0x44, 0x20, 0x00, 0x80]),
507            };
508            roundtrip(&packet);
509        }
510    }
511}