Skip to main content

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