1use core::marker::PhantomData;
7use tbytes::{TBytesReader, TBytesReaderFor};
8
9use crate::consts::{
10 CHECKSUM_SIZE, HEADER_MAX_SIZE, HEADER_MIN_SIZE, HEADER_V1_SIZE, HEADER_V2_SIZE,
11 SIGNATURE_LENGTH,
12};
13use crate::error::VersionError;
14use crate::io::{AsyncRead, AsyncWrite, Read, Write};
15use crate::protocol::marker::{HasCompId, HasMsgId, HasPayloadLen, HasSysId, Sequenced, Unset};
16use crate::protocol::{
17 CompatFlags, ComponentId, HeaderBuilder, IncompatFlags, MavSTX, MaybeVersioned, PayloadLength,
18 Sequence, SystemId, Versioned, Versionless, V2,
19};
20use crate::protocol::{MavLinkVersion, MessageId};
21
22use crate::prelude::*;
23
24#[derive(Clone, Copy, Debug, Default)]
41#[cfg_attr(feature = "specta", derive(specta::Type))]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub struct Header<V: MaybeVersioned> {
44 pub(super) version: MavLinkVersion,
45 pub(super) payload_length: PayloadLength,
46 pub(super) incompat_flags: IncompatFlags,
47 pub(super) compat_flags: CompatFlags,
48 pub(super) sequence: Sequence,
49 pub(super) system_id: SystemId,
50 pub(super) component_id: ComponentId,
51 pub(super) message_id: MessageId,
52 pub(super) _marker_version: PhantomData<V>,
53}
54
55impl<V: MaybeVersioned> Header<V> {
56 #[inline]
62 pub fn version(&self) -> MavLinkVersion {
63 self.version
64 }
65
66 #[inline]
70 pub fn payload_length(&self) -> PayloadLength {
71 self.payload_length
72 }
73
74 #[inline]
78 pub fn sequence(&self) -> Sequence {
79 self.sequence
80 }
81
82 #[inline]
89 pub fn system_id(&self) -> SystemId {
90 self.system_id
91 }
92
93 #[inline]
102 pub fn component_id(&self) -> ComponentId {
103 self.component_id
104 }
105
106 #[inline]
110 pub fn message_id(&self) -> MessageId {
111 self.message_id
112 }
113
114 pub fn size(&self) -> usize {
118 match self.version {
119 MavLinkVersion::V1 => HEADER_V1_SIZE,
120 MavLinkVersion::V2 => HEADER_V2_SIZE,
121 }
122 }
123
124 pub fn is_signed(&self) -> bool {
134 match self.version {
135 MavLinkVersion::V1 => false,
136 MavLinkVersion::V2 => self
137 .incompat_flags
138 .contains(IncompatFlags::MAVLINK_IFLAG_SIGNED),
139 }
140 }
141
142 #[inline]
146 pub(super) fn set_is_signed(&mut self, flag: bool) {
147 self.incompat_flags
148 .set(IncompatFlags::MAVLINK_IFLAG_SIGNED, flag);
149 }
150
151 pub fn body_length(&self) -> usize {
161 match self.version {
162 MavLinkVersion::V1 => self.payload_length as usize + CHECKSUM_SIZE,
163 MavLinkVersion::V2 => {
164 if self.is_signed() {
165 self.payload_length as usize + CHECKSUM_SIZE + SIGNATURE_LENGTH
166 } else {
167 self.payload_length as usize + CHECKSUM_SIZE
168 }
169 }
170 }
171 }
172
173 pub fn try_into_versioned<Version: MaybeVersioned>(
178 self,
179 ) -> core::result::Result<Header<Version>, VersionError> {
180 Version::expect(self.version)?;
181
182 Ok(Header {
183 version: self.version,
184 payload_length: self.payload_length,
185 incompat_flags: self.incompat_flags,
186 compat_flags: self.compat_flags,
187 sequence: self.sequence,
188 system_id: self.system_id,
189 component_id: self.component_id,
190 message_id: self.message_id,
191 _marker_version: PhantomData,
192 })
193 }
194
195 pub fn try_to_versioned<Version: MaybeVersioned>(
200 &self,
201 ) -> core::result::Result<Header<Version>, VersionError> {
202 self.clone().try_into_versioned()
203 }
204
205 pub fn into_versionless(self) -> Header<Versionless> {
207 Header {
208 version: self.version,
209 payload_length: self.payload_length,
210 incompat_flags: self.incompat_flags,
211 compat_flags: self.compat_flags,
212 sequence: self.sequence,
213 system_id: self.system_id,
214 component_id: self.component_id,
215 message_id: self.message_id,
216 _marker_version: PhantomData,
217 }
218 }
219
220 pub fn to_versionless(&self) -> Header<Versionless> {
222 self.clone().into_versionless()
223 }
224
225 pub(super) fn send<E: Into<Error>, W: Write<E>>(
226 &self,
227 writer: &mut W,
228 ) -> core::result::Result<usize, E> {
229 writer.write_all(self.serialize().as_slice())?;
230 Ok(self.size())
231 }
232
233 pub(super) async fn send_async<E: Into<Error>, W: AsyncWrite<E>>(
234 &self,
235 writer: &mut W,
236 ) -> core::result::Result<usize, E> {
237 writer.write_all(self.serialize().as_slice()).await?;
238 Ok(self.size())
239 }
240
241 fn dump_bytes(&self, header_bytes: &mut HeaderBytes) {
242 match self.version {
243 MavLinkVersion::V1 => self.dump_v1_bytes(header_bytes),
244 MavLinkVersion::V2 => self.dump_v2_bytes(header_bytes),
245 };
246 }
247
248 fn dump_v1_bytes(&self, header_bytes: &mut HeaderBytes) {
249 header_bytes.buffer[0] = MavSTX::V1.into();
250 header_bytes.buffer[1] = self.payload_length;
251 header_bytes.buffer[2] = self.sequence;
252 header_bytes.buffer[3] = self.system_id;
253 header_bytes.buffer[4] = self.component_id;
254 header_bytes.buffer[5] = self.message_id.to_le_bytes()[0];
255 }
256
257 fn dump_v2_bytes(&self, header_bytes: &mut HeaderBytes) {
258 let message_id: [u8; 4] = self.message_id.to_le_bytes();
259
260 header_bytes.buffer[0] = MavSTX::V2.into();
261 header_bytes.buffer[1] = self.payload_length;
262 header_bytes.buffer[2] = self.incompat_flags.bits();
263 header_bytes.buffer[3] = self.compat_flags.bits();
264 header_bytes.buffer[4] = self.sequence;
265 header_bytes.buffer[5] = self.system_id;
266 header_bytes.buffer[6] = self.component_id;
267 header_bytes.buffer[7..10].copy_from_slice(&message_id[0..3]);
268 }
269}
270
271impl<V: MaybeVersioned> Header<V> {
272 pub(super) fn serialize(&self) -> HeaderBytes {
273 let mut header_bytes = HeaderBytes {
274 size: self.size(),
275 ..Default::default()
276 };
277 self.dump_bytes(&mut header_bytes);
278 header_bytes
279 }
280
281 pub(super) fn deserialize(buf: &[u8]) -> core::result::Result<Header<V>, FrameError> {
282 if buf.len() < HEADER_MIN_SIZE {
283 return Err(FrameError::InvalidHeader);
284 }
285
286 let header_length = match MavSTX::from(buf[0]) {
287 MavSTX::V1 => HEADER_V1_SIZE,
288 MavSTX::V2 => HEADER_V2_SIZE,
289 MavSTX::Unknown(_) => return Err(FrameError::InvalidHeader),
290 };
291
292 if buf.len() < header_length {
293 return Err(FrameError::InvalidHeader);
294 }
295
296 Ok(unsafe { Header::<V>::try_from_slice_unchecked(&buf[0..header_length]) })
297 }
298
299 pub(super) fn recv<E: Into<Error>, R: Read<E>>(
300 reader: &mut R,
301 ) -> core::result::Result<Header<V>, E> {
302 loop {
303 let mut buffer = [0u8; HEADER_MIN_SIZE];
304 reader.read_exact(&mut buffer)?;
305
306 if let Some(mut header_start) = HeaderStart::<V>::from_slice(&buffer) {
307 if !header_start.is_complete() {
308 reader.read_exact(header_start.remaining_bytes_mut())?;
309 }
310 return Ok(unsafe {
311 Header::<V>::try_from_slice_unchecked(header_start.as_slice_unchecked())
312 });
313 } else {
314 continue;
315 }
316 }
317 }
318
319 pub(super) async fn recv_async<E: Into<Error>, R: AsyncRead<E>>(
320 reader: &mut R,
321 ) -> core::result::Result<Header<V>, E> {
322 loop {
323 let mut buffer = [0u8; HEADER_MIN_SIZE];
324 reader.read_exact(&mut buffer).await?;
325
326 if let Some(mut header_start) = HeaderStart::<V>::from_slice(&buffer) {
327 if !header_start.is_complete() {
328 reader
329 .read_exact(header_start.remaining_bytes_mut())
330 .await?;
331 }
332 return Ok(unsafe {
333 Header::<V>::try_from_slice_unchecked(header_start.as_slice_unchecked())
334 });
335 } else {
336 continue;
337 }
338 }
339 }
340
341 unsafe fn try_from_slice_unchecked(bytes: &[u8]) -> Header<V> {
344 let reader = TBytesReader::from(bytes);
345
346 let magic: u8 = reader.read().unwrap();
347 let mavlink_version: MavLinkVersion = MavSTX::from(magic).to_mavlink_version().unwrap();
348 let payload_length: u8 = reader.read().unwrap();
349
350 let (incompat_flags, compat_flags) = if let MavLinkVersion::V2 = mavlink_version {
351 let incompat_flags = reader.read().unwrap();
352 let compat_flags = reader.read().unwrap();
353 (
354 IncompatFlags::from_bits_truncate(incompat_flags),
355 CompatFlags::from_bits_truncate(compat_flags),
356 )
357 } else {
358 (IncompatFlags::default(), CompatFlags::default())
359 };
360
361 let sequence: u8 = reader.read().unwrap();
362 let system_id: u8 = reader.read().unwrap();
363 let component_id: u8 = reader.read().unwrap();
364
365 let message_id: MessageId = match mavlink_version {
366 MavLinkVersion::V1 => {
367 let version: u8 = reader.read().unwrap();
368 version as MessageId
369 }
370 MavLinkVersion::V2 => {
371 let version_byte: [u8; 4] = [
372 reader.read().unwrap(),
373 reader.read().unwrap(),
374 reader.read().unwrap(),
375 0,
376 ];
377 MessageId::from_le_bytes(version_byte)
378 }
379 };
380
381 let mut header_bytes = [0u8; HEADER_MAX_SIZE];
382 header_bytes[0..bytes.len()].copy_from_slice(bytes);
383
384 Header {
385 version: mavlink_version,
386 payload_length,
387 incompat_flags,
388 compat_flags,
389 sequence,
390 system_id,
391 component_id,
392 message_id,
393 _marker_version: PhantomData,
394 }
395 }
396}
397
398impl<V: Versioned> Header<V> {
399 pub(super) fn to_builder(
400 &self,
401 ) -> HeaderBuilder<V, HasPayloadLen, Sequenced, HasSysId, HasCompId, HasMsgId> {
402 let mut incompat_flags = self.incompat_flags;
403 incompat_flags.set(IncompatFlags::MAVLINK_IFLAG_SIGNED, false);
404
405 HeaderBuilder {
406 mavlink_version: PhantomData,
407 payload_length: HasPayloadLen(self.payload_length),
408 incompat_flags: Some(incompat_flags),
409 compat_flags: Some(self.compat_flags),
410 sequence: Sequenced(self.sequence),
411 system_id: HasSysId(self.system_id),
412 component_id: HasCompId(self.component_id),
413 message_id: HasMsgId(self.message_id),
414 }
415 }
416}
417
418impl Header<V2> {
419 #[inline]
426 pub fn incompat_flags(&self) -> IncompatFlags {
427 self.incompat_flags
428 }
429
430 #[inline]
437 pub fn compat_flags(&self) -> CompatFlags {
438 self.compat_flags
439 }
440}
441
442impl Header<Versionless> {
443 pub fn builder() -> HeaderBuilder<Versionless, Unset, Unset, Unset, Unset, Unset> {
451 HeaderBuilder::new()
452 }
453
454 #[inline]
461 pub fn incompat_flags(&self) -> Option<IncompatFlags> {
462 match self.version() {
463 MavLinkVersion::V1 => None,
464 MavLinkVersion::V2 => Some(self.incompat_flags),
465 }
466 }
467
468 #[inline]
475 pub fn compat_flags(&self) -> Option<CompatFlags> {
476 match self.version() {
477 MavLinkVersion::V1 => None,
478 MavLinkVersion::V2 => Some(self.compat_flags),
479 }
480 }
481}
482
483struct HeaderStart<V: MaybeVersioned> {
485 buffer: [u8; HEADER_MAX_SIZE],
486 n_bytes_read: usize,
487 n_bytes_left: usize,
488 _marker_version: PhantomData<V>,
489}
490
491impl<V: MaybeVersioned> HeaderStart<V> {
492 fn from_slice(buffer: &[u8]) -> Option<Self> {
494 let (mavlink_version, header_start_idx) = {
495 let mut mavlink_version: Option<MavLinkVersion> = None;
496 let mut header_start_idx = buffer.len();
497 for (i, &byte) in buffer.iter().enumerate() {
498 if V::is_magic_byte(byte) {
499 header_start_idx = i;
500 mavlink_version = MavSTX::from(byte).into();
501 break;
502 }
503 }
504
505 (mavlink_version, header_start_idx)
506 };
507
508 match mavlink_version {
509 None => None,
510 Some(version) => {
511 let header_size = match version {
512 MavLinkVersion::V1 => HEADER_V1_SIZE,
513 MavLinkVersion::V2 => HEADER_V2_SIZE,
514 };
515
516 let n_bytes_to_read = core::cmp::min(buffer.len() - header_start_idx, header_size);
517 let header_start_bytes =
518 &buffer[header_start_idx..header_start_idx + n_bytes_to_read];
519
520 let mut header_bytes = [0u8; HEADER_MAX_SIZE];
521 header_bytes[0..n_bytes_to_read].copy_from_slice(header_start_bytes);
522
523 Some(Self {
524 buffer: header_bytes,
525 n_bytes_read: n_bytes_to_read,
526 n_bytes_left: header_size - n_bytes_to_read,
527 _marker_version: PhantomData,
528 })
529 }
530 }
531 }
532
533 unsafe fn as_slice_unchecked(&self) -> &[u8] {
537 &self.buffer[0..self.n_bytes_read + self.n_bytes_left]
538 }
539
540 fn is_complete(&self) -> bool {
542 self.n_bytes_left == 0
543 }
544
545 fn remaining_bytes_mut(&mut self) -> &mut [u8] {
547 &mut self.buffer[self.n_bytes_read..self.n_bytes_read + self.n_bytes_left]
548 }
549}
550
551#[derive(Clone, Copy, Debug, Default)]
553#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
554pub(super) struct HeaderBytes {
555 buffer: [u8; HEADER_MAX_SIZE],
556 size: usize,
557}
558
559impl HeaderBytes {
560 pub(super) fn as_slice(&self) -> &[u8] {
564 &self.buffer[0..self.size]
565 }
566
567 pub(super) fn size(&self) -> usize {
569 self.size
570 }
571
572 pub(super) fn crc_data(&self) -> &[u8] {
581 &self.buffer[1..self.size()]
582 }
583}
584
585#[cfg(test)]
586mod header_tests {
587 use super::*;
588
589 #[cfg(feature = "std")]
590 use std::io::Cursor;
591
592 use crate::consts::{STX_V1, STX_V2};
593
594 #[cfg(feature = "std")]
595 use crate::io::StdIoReader;
596
597 #[test]
598 #[cfg(feature = "std")]
599 fn read_v1_header() {
600 let buffer = vec![
601 12, 24, 240, STX_V1, 8, 1, 10, 255, 0, ];
611 let mut reader = StdIoReader::new(Cursor::new(buffer));
612
613 let header = Header::<V1>::recv(&mut reader).unwrap();
614 let header = header.try_into_versioned::<V1>().unwrap();
615
616 assert!(header.try_into_versioned::<V2>().is_err());
617 assert!(matches!(header.version(), MavLinkVersion::V1));
618
619 assert_eq!(header.payload_length(), 8u8);
620 assert_eq!(header.sequence(), 1u8);
621 assert_eq!(header.system_id(), 10u8);
622 assert_eq!(header.component_id(), 255u8);
623 assert_eq!(header.message_id(), 0u32);
624 }
625
626 #[test]
627 #[cfg(feature = "std")]
628 fn read_v2_header() {
629 let buffer = vec![
630 12, 24, 240, STX_V2, 8, 1, 0, 1, 10, 255, 0, 0, 0, ];
644 let mut reader = StdIoReader::new(Cursor::new(buffer));
645
646 let header = Header::<Versionless>::recv(&mut reader).unwrap();
647 let header = header.try_into_versioned::<V2>().unwrap();
648
649 assert!(header.try_into_versioned::<V1>().is_err());
650 assert!(matches!(header.version(), MavLinkVersion::V2));
651
652 assert_eq!(header.payload_length(), 8u8);
653 assert_eq!(header.incompat_flags(), IncompatFlags::MAVLINK_IFLAG_SIGNED);
654 assert_eq!(header.compat_flags(), CompatFlags::default());
655 assert_eq!(header.sequence(), 1u8);
656 assert_eq!(header.system_id(), 10u8);
657 assert_eq!(header.component_id(), 255u8);
658 assert_eq!(header.message_id(), 0u32);
659 }
660
661 #[test]
662 #[cfg(feature = "std")]
663 fn read_v2_header_magic_bytes_in_sequence() {
664 let buffer = vec![
665 12, 24, 240, STX_V2, 8, 1, 0, STX_V2, 10, 255, 0, 0, 0, ];
679 let mut reader = StdIoReader::new(Cursor::new(buffer));
680
681 let header = Header::<V2>::recv(&mut reader).unwrap();
682
683 assert!(header.try_into_versioned::<V1>().is_err());
684 assert!(matches!(header.version(), MavLinkVersion::V2));
685
686 assert_eq!(header.payload_length(), 8u8);
687 assert_eq!(header.incompat_flags(), IncompatFlags::MAVLINK_IFLAG_SIGNED);
688 assert_eq!(header.compat_flags(), CompatFlags::default());
689 assert_eq!(header.sequence(), STX_V2);
690 assert_eq!(header.system_id(), 10u8);
691 assert_eq!(header.component_id(), 255u8);
692 assert_eq!(header.message_id(), 0u32);
693 }
694
695 #[test]
696 fn build_v1_header() {
697 let header = Header::builder()
698 .payload_length(10)
699 .sequence(5)
700 .system_id(10)
701 .component_id(240)
702 .message_id(42)
703 .version(V1)
704 .build();
705
706 assert!(matches!(header.version(), MavLinkVersion::V1));
707 assert_eq!(header.payload_length(), 10);
708 assert_eq!(header.sequence(), 5);
709 assert_eq!(header.system_id(), 10);
710 assert_eq!(header.component_id(), 240);
711 assert_eq!(header.message_id(), 42);
712 }
713
714 #[test]
715 fn build_v2_header() {
716 let header = Header::builder()
717 .incompat_flags(IncompatFlags::MAVLINK_IFLAG_SIGNED)
718 .compat_flags(CompatFlags::BIT_4 | CompatFlags::BIT_7)
719 .payload_length(10)
720 .sequence(5)
721 .system_id(10)
722 .component_id(240)
723 .message_id(42)
724 .signed(true)
725 .build();
726
727 assert!(matches!(header.version(), MavLinkVersion::V2));
728 assert_eq!(header.incompat_flags(), IncompatFlags::MAVLINK_IFLAG_SIGNED);
729 assert_eq!(
730 header.compat_flags(),
731 CompatFlags::BIT_4 | CompatFlags::BIT_7
732 );
733 assert_eq!(header.payload_length(), 10);
734 assert_eq!(header.sequence(), 5);
735 assert_eq!(header.system_id(), 10);
736 assert_eq!(header.component_id(), 240);
737 assert_eq!(header.message_id(), 42);
738 }
739
740 #[test]
741 fn serialize_deserialize_v1_test() {
742 let sequence = [
743 STX_V1, 8, 1, 10, 255, 42, 41, 41, 41, ];
753 let header_bytes = &sequence[0..HEADER_V1_SIZE];
754
755 let header: Header<V1> = Header::deserialize(&header_bytes).unwrap();
757 assert_eq!(header.payload_length(), 8);
758 assert_eq!(header.component_id(), 255);
759 assert_eq!(header.message_id(), 42);
760
761 let serialized = header.serialize();
763 assert_eq!(serialized.as_slice(), header_bytes);
764
765 let header: Header<V1> = Header::deserialize(&sequence).unwrap();
767 let serialized = header.serialize();
768 assert_eq!(serialized.as_slice(), header_bytes);
769
770 assert!(matches!(
772 Header::<V1>::deserialize(&header_bytes[0..header_bytes.len() - 2]),
773 Err(FrameError::InvalidHeader)
774 ));
775 }
776
777 #[test]
778 fn serialize_deserialize_v2_test() {
779 let sequence = [
780 STX_V2, 8, 1, 0, 42, 10, 255, 2, 1, 0, ];
791 let header_bytes = &sequence[0..HEADER_V2_SIZE];
792
793 let header: Header<V2> = Header::deserialize(&header_bytes).unwrap();
795 assert_eq!(header.payload_length(), 8);
796 assert_eq!(header.component_id(), 255);
797 assert_eq!(header.message_id(), 258);
798
799 let serialized = header.serialize();
801 assert_eq!(serialized.as_slice(), header_bytes);
802
803 let header: Header<V2> = Header::deserialize(&sequence).unwrap();
805 let serialized = header.serialize();
806 assert_eq!(serialized.as_slice(), header_bytes);
807
808 assert!(matches!(
810 Header::<V2>::deserialize(&header_bytes[0..header_bytes.len() - 2]),
811 Err(FrameError::InvalidHeader)
812 ));
813 }
814
815 #[test]
816 fn header_start_v2_test() {
817 let v2_sequence = [
818 STX_V2, 8, 1, 0, 42, 10, 255, 2, 1, 0, 41, 41, 41, ];
832
833 let header_start = HeaderStart::<V2>::from_slice(&v2_sequence).unwrap();
835 assert!(header_start.is_complete());
836
837 let header: Header<V2> =
838 Header::deserialize(unsafe { header_start.as_slice_unchecked() }).unwrap();
839 assert_eq!(header.payload_length(), 8);
840 assert_eq!(header.component_id(), 255);
841 assert_eq!(header.message_id(), 258);
842
843 let mut header_start = HeaderStart::<V2>::from_slice(&v2_sequence[0..5]).unwrap();
845 assert!(!header_start.is_complete());
846
847 let n_bytes_left = header_start.n_bytes_left;
848 header_start
849 .remaining_bytes_mut()
850 .copy_from_slice(&v2_sequence[5..5 + n_bytes_left]);
851
852 let header: Header<V2> =
853 Header::deserialize(unsafe { header_start.as_slice_unchecked() }).unwrap();
854 assert_eq!(header.payload_length(), 8);
855 assert_eq!(header.component_id(), 255);
856 assert_eq!(header.message_id(), 258);
857 }
858}