cu_msp_lib/
lib.rs

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