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