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