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}
35impl 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#[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#[derive(Copy, Clone, Debug, PartialEq)]
109pub enum MspPacketDirection {
110 ToFlightController,
112 FromFlightController,
114 Unsupported,
116}
117
118impl MspPacketDirection {
119 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)]
144pub 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
172pub 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 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 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 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, 62 => self.packet_direction = MspPacketDirection::FromFlightController, 33 => self.packet_direction = MspPacketDirection::Unsupported, _ => {
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 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 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 pub fn packet_size_bytes_v2(&self) -> usize {
474 let MspPacketData(data) = &self.data;
475 9 + data.len()
476 }
477
478 pub fn packet_size_bytes_v2_over_v1(&self) -> usize {
480 let MspPacketData(data) = &self.data;
481 12 + data.len()
482 }
483
484 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 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 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; 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}