cu_msp_lib/
lib.rs

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