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