1#![cfg_attr(not(feature = "std"), no_std)]
83#![cfg_attr(docsrs, feature(doc_cfg))]
84#![deny(clippy::all)]
85#![warn(clippy::use_self)]
86
87use core::result::Result;
88
89#[cfg(feature = "std")]
90use std::io::{Read, Write};
91
92pub mod utils;
93#[allow(unused_imports)]
94use utils::{RustDefault, remove_trailing_zeroes};
95
96#[cfg(feature = "serde")]
97use serde::{Deserialize, Serialize};
98
99pub mod peek_reader;
100use peek_reader::PeekReader;
101
102use crate::{
103 bytes::Bytes,
104 error::{MessageReadError, MessageWriteError, ParserError},
105};
106
107use crc_any::CRCu16;
108
109#[doc(hidden)]
110pub mod bytes;
111#[doc(hidden)]
112pub mod bytes_mut;
113#[cfg(any(feature = "std", feature = "tokio"))]
114mod connection;
115pub mod consts;
116pub mod error;
117pub mod types;
118#[cfg(feature = "std")]
119pub use self::connection::{Connectable, Connection, MavConnection, connect};
120
121#[cfg(feature = "tokio")]
122pub use self::connection::{AsyncConnectable, AsyncMavConnection, connect_async};
123
124#[cfg(feature = "tokio")]
125pub mod async_peek_reader;
126#[cfg(feature = "tokio")]
127use async_peek_reader::AsyncPeekReader;
128#[cfg(feature = "tokio")]
129use tokio::io::{AsyncWrite, AsyncWriteExt};
130
131#[cfg(all(feature = "embedded", not(feature = "std")))]
132pub mod embedded;
133#[cfg(all(feature = "embedded", not(feature = "std")))]
134use embedded::{Read, Write};
135
136#[cfg(not(feature = "mav2-message-signing"))]
137type SigningData = ();
138#[cfg(feature = "mav2-message-signing")]
139mod signing;
140#[cfg(feature = "mav2-message-signing")]
141pub use self::signing::{SigningConfig, SigningData};
142#[cfg(feature = "mav2-message-signing")]
143use sha2::{Digest, Sha256};
144
145#[cfg(feature = "arbitrary")]
146use arbitrary::Arbitrary;
147
148#[cfg(any(feature = "std", feature = "tokio"))]
149mod connectable;
150
151#[cfg(any(feature = "std", feature = "tokio"))]
152mod connection_shared;
153
154#[cfg(any(feature = "std", feature = "tokio"))]
155pub use connectable::ConnectionAddress;
156
157#[cfg(feature = "transport-direct-serial")]
158pub use connection::direct_serial::config::SerialConfig;
159
160#[cfg(feature = "transport-tcp")]
161pub use connection::tcp::config::{TcpConfig, TcpMode};
162
163#[cfg(feature = "transport-udp")]
164pub use connection::udp::config::{UdpConfig, UdpMode};
165
166#[cfg(feature = "std")]
167pub use connection::file::config::FileConfig;
168
169pub trait Message
174where
175 Self: Sized,
176{
177 fn message_id(&self) -> u32;
179
180 fn message_name(&self) -> &'static str;
182
183 fn target_system_id(&self) -> Option<u8>;
185
186 fn target_component_id(&self) -> Option<u8>;
188
189 fn ser(&self, version: MavlinkVersion, bytes: &mut [u8]) -> usize;
195
196 fn parse(version: MavlinkVersion, msgid: u32, payload: &[u8]) -> Result<Self, ParserError>;
205
206 fn message_id_from_name(name: &str) -> Option<u32>;
208 fn default_message_from_id(id: u32) -> Option<Self>;
210 #[cfg(feature = "arbitrary")]
212 fn random_message_from_id<R: rand::TryRng<Error = std::convert::Infallible>>(
213 id: u32,
214 rng: &mut R,
215 ) -> Option<Self>;
216 fn extra_crc(id: u32) -> u8;
218}
219
220pub trait MessageData: Sized {
221 type Message: Message;
222
223 const ID: u32;
224 const NAME: &'static str;
225 const EXTRA_CRC: u8;
226 const ENCODED_LEN: usize;
227
228 fn ser(&self, version: MavlinkVersion, payload: &mut [u8]) -> usize;
232 fn deser(version: MavlinkVersion, payload: &[u8]) -> Result<Self, ParserError>;
236}
237
238#[derive(Debug, Copy, Clone, PartialEq, Eq)]
240#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
241#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
242pub struct MavHeader {
243 pub system_id: u8,
245 pub component_id: u8,
247 pub sequence: u8,
249}
250
251#[derive(Debug, Copy, Clone, PartialEq, Eq)]
253#[cfg_attr(feature = "serde", derive(Serialize))]
254#[cfg_attr(feature = "serde", serde(tag = "type"))]
255#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
256pub enum MavlinkVersion {
257 V1,
259 V2,
261}
262
263pub const MAV_STX: u8 = 0xFE;
265
266pub const MAV_STX_V2: u8 = 0xFD;
268
269impl Default for MavHeader {
272 fn default() -> Self {
273 Self {
274 system_id: 255,
275 component_id: 0,
276 sequence: 0,
277 }
278 }
279}
280
281#[derive(Debug, Clone)]
285#[cfg_attr(feature = "serde", derive(Serialize))]
286#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
287pub struct MavFrame<M: Message> {
288 pub header: MavHeader,
290 pub msg: M,
292 pub protocol_version: MavlinkVersion,
294}
295
296impl<M: Message> MavFrame<M> {
297 pub fn ser(&self, buf: &mut [u8]) -> usize {
306 let mut buf = bytes_mut::BytesMut::new(buf);
307
308 buf.put_slice(&[
327 self.header.sequence,
328 self.header.system_id,
329 self.header.component_id,
330 ]);
331
332 match self.protocol_version {
334 MavlinkVersion::V2 => buf.put_u24_le(self.msg.message_id()),
335 MavlinkVersion::V1 => buf.put_u8(
336 self.msg
337 .message_id()
338 .try_into()
339 .expect("message is MAVLink 2 only"),
340 ),
341 }
342
343 let header_len = buf.len();
344 let payload_len = self.msg.ser(self.protocol_version, &mut buf[header_len..]);
347
348 header_len + payload_len
349 }
350
351 pub fn deser(version: MavlinkVersion, input: &[u8]) -> Result<Self, ParserError> {
360 let mut buf = Bytes::new(input);
361
362 let sequence = buf.get_u8()?;
372 let system_id = buf.get_u8()?;
373 let component_id = buf.get_u8()?;
374 let header = MavHeader {
375 system_id,
376 component_id,
377 sequence,
378 };
379
380 let msg_id = match version {
381 MavlinkVersion::V2 => buf.get_u24_le()?,
382 MavlinkVersion::V1 => buf.get_u8()?.into(),
383 };
384
385 M::parse(version, msg_id, buf.remaining_bytes()).map(|msg| Self {
386 header,
387 msg,
388 protocol_version: version,
389 })
390 }
391
392 pub fn header(&self) -> MavHeader {
394 self.header
395 }
396}
397
398pub fn calculate_crc(data: &[u8], extra_crc: u8) -> u16 {
400 let mut crc_calculator = CRCu16::crc16mcrf4cc();
401 crc_calculator.digest(data);
402
403 crc_calculator.digest(&[extra_crc]);
404 crc_calculator.get_crc()
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq)]
408pub enum ReadVersion {
410 Single(MavlinkVersion),
412 Any,
414}
415
416impl From<MavlinkVersion> for ReadVersion {
417 fn from(value: MavlinkVersion) -> Self {
418 Self::Single(value)
419 }
420}
421
422pub fn read_versioned_msg<M: Message, R: Read>(
428 r: &mut PeekReader<R>,
429 version: ReadVersion,
430) -> Result<(MavHeader, M), MessageReadError> {
431 match version {
432 ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg(r),
433 ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg(r),
434 ReadVersion::Any => read_any_msg(r),
435 }
436}
437
438pub fn read_versioned_raw_message<M: Message, R: Read>(
444 r: &mut PeekReader<R>,
445 version: ReadVersion,
446) -> Result<MAVLinkMessageRaw, MessageReadError> {
447 match version {
448 ReadVersion::Single(MavlinkVersion::V2) => {
449 Ok(MAVLinkMessageRaw::V2(read_v2_raw_message::<M, _>(r)?))
450 }
451 ReadVersion::Single(MavlinkVersion::V1) => {
452 Ok(MAVLinkMessageRaw::V1(read_v1_raw_message::<M, _>(r)?))
453 }
454 ReadVersion::Any => read_any_raw_message::<M, _>(r),
455 }
456}
457
458#[cfg(feature = "tokio")]
464pub async fn read_versioned_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
465 r: &mut AsyncPeekReader<R>,
466 version: ReadVersion,
467) -> Result<(MavHeader, M), MessageReadError> {
468 match version {
469 ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_async(r).await,
470 ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg_async(r).await,
471 ReadVersion::Any => read_any_msg_async(r).await,
472 }
473}
474
475#[cfg(feature = "tokio")]
481pub async fn read_versioned_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
482 r: &mut AsyncPeekReader<R>,
483 version: ReadVersion,
484) -> Result<MAVLinkMessageRaw, MessageReadError> {
485 match version {
486 ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
487 read_v2_raw_message_async::<M, _>(r).await?,
488 )),
489 ReadVersion::Single(MavlinkVersion::V1) => Ok(MAVLinkMessageRaw::V1(
490 read_v1_raw_message_async::<M, _>(r).await?,
491 )),
492 ReadVersion::Any => read_any_raw_message_async::<M, _>(r).await,
493 }
494}
495
496#[cfg(feature = "mav2-message-signing")]
505pub fn read_versioned_raw_message_signed<M: Message, R: Read>(
506 r: &mut PeekReader<R>,
507 version: ReadVersion,
508 signing_data: Option<&SigningData>,
509) -> Result<MAVLinkMessageRaw, MessageReadError> {
510 match version {
511 ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
512 read_v2_raw_message_inner::<M, _>(r, signing_data)?,
513 )),
514 ReadVersion::Single(MavlinkVersion::V1) => {
515 Ok(MAVLinkMessageRaw::V1(read_v1_raw_message::<M, _>(r)?))
516 }
517 ReadVersion::Any => read_any_raw_message_inner::<M, _>(r, signing_data),
518 }
519}
520
521#[cfg(feature = "mav2-message-signing")]
530pub fn read_versioned_msg_signed<M: Message, R: Read>(
531 r: &mut PeekReader<R>,
532 version: ReadVersion,
533 signing_data: Option<&SigningData>,
534) -> Result<(MavHeader, M), MessageReadError> {
535 match version {
536 ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_inner(r, signing_data),
537 ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg(r),
538 ReadVersion::Any => read_any_msg_inner(r, signing_data),
539 }
540}
541
542#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
551pub async fn read_versioned_raw_message_async_signed<
552 M: Message,
553 R: tokio::io::AsyncRead + Unpin,
554>(
555 r: &mut AsyncPeekReader<R>,
556 version: ReadVersion,
557 signing_data: Option<&SigningData>,
558) -> Result<MAVLinkMessageRaw, MessageReadError> {
559 match version {
560 ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
561 read_v2_raw_message_async_inner::<M, _>(r, signing_data).await?,
562 )),
563 ReadVersion::Single(MavlinkVersion::V1) => Ok(MAVLinkMessageRaw::V1(
564 read_v1_raw_message_async::<M, _>(r).await?,
565 )),
566 ReadVersion::Any => read_any_raw_message_async_inner::<M, _>(r, signing_data).await,
567 }
568}
569
570#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
579pub async fn read_versioned_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
580 r: &mut AsyncPeekReader<R>,
581 version: ReadVersion,
582 signing_data: Option<&SigningData>,
583) -> Result<(MavHeader, M), MessageReadError> {
584 match version {
585 ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_async_inner(r, signing_data).await,
586 ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg_async(r).await,
587 ReadVersion::Any => read_any_msg_async_inner(r, signing_data).await,
588 }
589}
590
591#[derive(Debug, Copy, Clone, PartialEq, Eq)]
592pub struct MAVLinkV1MessageRaw([u8; consts::v1::FRAME_SIZE]);
597
598impl Default for MAVLinkV1MessageRaw {
599 fn default() -> Self {
600 Self::new()
601 }
602}
603
604impl MAVLinkV1MessageRaw {
605 pub const fn new() -> Self {
607 Self([0; consts::v1::FRAME_SIZE])
608 }
609
610 pub const fn from_bytes_unparsed(bytes: [u8; consts::v1::FRAME_SIZE]) -> Self {
614 Self(bytes)
615 }
616
617 #[inline]
619 pub fn as_slice(&self) -> &[u8] {
620 &self.0
621 }
622
623 #[inline]
625 pub fn as_mut_slice(&mut self) -> &mut [u8] {
626 &mut self.0
627 }
628
629 #[inline]
631 pub fn into_inner(self) -> [u8; consts::v1::FRAME_SIZE] {
632 self.0
633 }
634
635 #[inline]
637 pub fn header(&self) -> &[u8] {
638 &self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE)]
639 }
640
641 #[inline]
643 fn mut_header(&mut self) -> &mut [u8] {
644 &mut self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE)]
645 }
646
647 #[inline]
649 pub fn payload_length(&self) -> u8 {
650 self.0[consts::PAYLOAD_LEN_OFFSET]
651 }
652
653 #[inline]
655 pub fn sequence(&self) -> u8 {
656 self.0[2]
657 }
658
659 #[inline]
661 pub fn system_id(&self) -> u8 {
662 self.0[3]
663 }
664
665 #[inline]
667 pub fn component_id(&self) -> u8 {
668 self.0[4]
669 }
670
671 #[inline]
673 pub fn message_id(&self) -> u8 {
674 self.0[5]
675 }
676
677 #[inline]
679 pub fn payload(&self) -> &[u8] {
680 let payload_length: usize = self.payload_length().into();
681 let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
682 &self.0[payload_offset..(payload_offset + payload_length)]
683 }
684
685 #[inline]
687 pub fn checksum(&self) -> u16 {
688 let payload_length: usize = self.payload_length().into();
689 let checksum_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length;
690 u16::from_le_bytes([self.0[checksum_offset], self.0[checksum_offset + 1]])
691 }
692
693 #[inline]
694 fn mut_payload_and_checksum(&mut self) -> &mut [u8] {
695 let payload_length: usize = self.payload_length().into();
696 let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
697 &mut self.0[payload_offset..(payload_offset + payload_length + consts::CHECKSUM_SIZE)]
698 }
699
700 #[inline]
702 pub fn has_valid_crc<M: Message>(&self) -> bool {
703 let payload_length: usize = self.payload_length().into();
704 let crc_end = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length;
705 self.checksum()
706 == calculate_crc(
707 &self.0[consts::STX_SIZE..crc_end],
708 M::extra_crc(self.message_id().into()),
709 )
710 }
711
712 pub fn raw_bytes(&self) -> &[u8] {
714 let payload_length = self.payload_length() as usize;
715 let frame_len =
716 consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
717 &self.0[..frame_len]
718 }
719
720 fn serialize_stx_and_header_and_crc(
724 &mut self,
725 header: MavHeader,
726 msgid: u32,
727 payload_length: usize,
728 extra_crc: u8,
729 ) {
730 self.0[consts::STX_OFFSET] = MAV_STX;
731
732 let header_buf = self.mut_header();
733 header_buf.copy_from_slice(&[
734 payload_length as u8,
735 header.sequence,
736 header.system_id,
737 header.component_id,
738 msgid.try_into().unwrap(),
739 ]);
740
741 let crc = calculate_crc(
742 &self.0
743 [consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length)],
744 extra_crc,
745 );
746 self.0[(consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length)
747 ..(consts::STX_SIZE
748 + consts::v1::HEADER_SIZE
749 + payload_length
750 + consts::CHECKSUM_SIZE)]
751 .copy_from_slice(&crc.to_le_bytes());
752 }
753
754 pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
760 let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
761 let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
762 let payload_length = message.ser(MavlinkVersion::V1, payload_buf);
763
764 let message_id = message.message_id();
765 self.serialize_stx_and_header_and_crc(
766 header,
767 message_id,
768 payload_length,
769 M::extra_crc(message_id),
770 );
771 }
772
773 pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
777 let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
778 let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
779 let payload_length = message_data.ser(MavlinkVersion::V1, payload_buf);
780
781 self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC);
782 }
783}
784
785fn try_decode_v1<M: Message, R: Read>(
786 reader: &mut PeekReader<R>,
787) -> Result<Option<MAVLinkV1MessageRaw>, MessageReadError> {
788 let mut message = MAVLinkV1MessageRaw::new();
789 let whole_header_size = consts::STX_SIZE + consts::v1::HEADER_SIZE;
790
791 message.0[consts::STX_OFFSET] = MAV_STX;
792 let header = &reader.peek_exact(whole_header_size)?[consts::STX_SIZE..whole_header_size];
793 message.mut_header().copy_from_slice(header);
794 let packet_length = message.raw_bytes().len();
795 let payload_and_checksum = &reader.peek_exact(packet_length)?[whole_header_size..packet_length];
796 message
797 .mut_payload_and_checksum()
798 .copy_from_slice(payload_and_checksum);
799
800 if message.has_valid_crc::<M>() {
803 reader.consume(message.raw_bytes().len());
804 Ok(Some(message))
805 } else {
806 Ok(None)
807 }
808}
809
810#[cfg(feature = "tokio")]
811async fn try_decode_v1_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
813 reader: &mut AsyncPeekReader<R>,
814) -> Result<Option<MAVLinkV1MessageRaw>, MessageReadError> {
815 let mut message = MAVLinkV1MessageRaw::new();
816
817 message.0[consts::STX_OFFSET] = MAV_STX;
818 let header = &reader.peek_exact(consts::v1::HEADER_SIZE).await?[..consts::v1::HEADER_SIZE];
819 message.mut_header().copy_from_slice(header);
820 let packet_length = message.raw_bytes().len() - consts::STX_SIZE;
821 let payload_and_checksum =
822 &reader.peek_exact(packet_length).await?[consts::v1::HEADER_SIZE..packet_length];
823 message
824 .mut_payload_and_checksum()
825 .copy_from_slice(payload_and_checksum);
826
827 if message.has_valid_crc::<M>() {
830 reader.consume(message.raw_bytes().len() - consts::STX_SIZE);
831 Ok(Some(message))
832 } else {
833 Ok(None)
834 }
835}
836
837pub fn read_v1_raw_message<M: Message, R: Read>(
843 reader: &mut PeekReader<R>,
844) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
845 loop {
846 while reader.peek_exact(consts::STX_SIZE)?[consts::STX_OFFSET] != MAV_STX {
848 reader.consume(consts::STX_SIZE);
849 }
850
851 if let Some(msg) = try_decode_v1::<M, _>(reader)? {
852 return Ok(msg);
853 }
854
855 reader.consume(consts::STX_SIZE);
856 }
857}
858
859#[cfg(feature = "tokio")]
865pub async fn read_v1_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
866 reader: &mut AsyncPeekReader<R>,
867) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
868 loop {
869 loop {
870 if reader.read_u8().await? == MAV_STX {
872 break;
873 }
874 }
875
876 if let Some(message) = try_decode_v1_async::<M, _>(reader).await? {
877 return Ok(message);
878 }
879 }
880}
881
882#[cfg(all(feature = "embedded", not(feature = "std")))]
889pub async fn read_v1_raw_message_async<M: Message>(
890 reader: &mut impl embedded_io_async::Read,
891) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
892 loop {
893 let mut byte = [0u8; consts::STX_SIZE];
895 loop {
896 reader
897 .read_exact(&mut byte)
898 .await
899 .map_err(|_| MessageReadError::Io)?;
900 if byte[consts::STX_OFFSET] == MAV_STX {
901 break;
902 }
903 }
904
905 let mut message = MAVLinkV1MessageRaw::new();
906
907 message.0[consts::STX_OFFSET] = MAV_STX;
908 reader
909 .read_exact(message.mut_header())
910 .await
911 .map_err(|_| MessageReadError::Io)?;
912 reader
913 .read_exact(message.mut_payload_and_checksum())
914 .await
915 .map_err(|_| MessageReadError::Io)?;
916
917 if message.has_valid_crc::<M>() {
920 return Ok(message);
921 }
922 }
923}
924
925pub fn read_v1_msg<M: Message, R: Read>(
931 r: &mut PeekReader<R>,
932) -> Result<(MavHeader, M), MessageReadError> {
933 let message = read_v1_raw_message::<M, _>(r)?;
934
935 Ok((
936 MavHeader {
937 sequence: message.sequence(),
938 system_id: message.system_id(),
939 component_id: message.component_id(),
940 },
941 M::parse(
942 MavlinkVersion::V1,
943 u32::from(message.message_id()),
944 message.payload(),
945 )?,
946 ))
947}
948
949#[cfg(feature = "tokio")]
955pub async fn read_v1_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
956 r: &mut AsyncPeekReader<R>,
957) -> Result<(MavHeader, M), MessageReadError> {
958 let message = read_v1_raw_message_async::<M, _>(r).await?;
959
960 Ok((
961 MavHeader {
962 sequence: message.sequence(),
963 system_id: message.system_id(),
964 component_id: message.component_id(),
965 },
966 M::parse(
967 MavlinkVersion::V1,
968 u32::from(message.message_id()),
969 message.payload(),
970 )?,
971 ))
972}
973
974#[cfg(all(feature = "embedded", not(feature = "std")))]
979pub async fn read_v1_msg_async<M: Message>(
980 r: &mut impl embedded_io_async::Read,
981) -> Result<(MavHeader, M), MessageReadError> {
982 let message = read_v1_raw_message_async::<M>(r).await?;
983
984 Ok((
985 MavHeader {
986 sequence: message.sequence(),
987 system_id: message.system_id(),
988 component_id: message.component_id(),
989 },
990 M::parse(
991 MavlinkVersion::V1,
992 u32::from(message.message_id()),
993 message.payload(),
994 )?,
995 ))
996}
997
998#[derive(Debug, Copy, Clone, PartialEq, Eq)]
999pub struct MAVLinkV2MessageRaw([u8; consts::MAX_FRAME_SIZE]);
1004
1005impl Default for MAVLinkV2MessageRaw {
1006 fn default() -> Self {
1007 Self::new()
1008 }
1009}
1010
1011impl MAVLinkV2MessageRaw {
1012 pub const fn new() -> Self {
1014 Self([0; consts::MAX_FRAME_SIZE])
1015 }
1016
1017 pub const fn from_bytes_unparsed(bytes: [u8; consts::MAX_FRAME_SIZE]) -> Self {
1021 Self(bytes)
1022 }
1023
1024 #[inline]
1026 pub fn as_slice(&self) -> &[u8] {
1027 &self.0
1028 }
1029
1030 #[inline]
1032 pub fn as_mut_slice(&mut self) -> &mut [u8] {
1033 &mut self.0
1034 }
1035
1036 #[inline]
1038 pub fn into_inner(self) -> [u8; consts::MAX_FRAME_SIZE] {
1039 self.0
1040 }
1041
1042 #[inline]
1044 pub fn header(&self) -> &[u8] {
1045 &self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE)]
1046 }
1047
1048 #[inline]
1050 fn mut_header(&mut self) -> &mut [u8] {
1051 &mut self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE)]
1052 }
1053
1054 #[inline]
1056 pub fn payload_length(&self) -> u8 {
1057 self.0[consts::PAYLOAD_LEN_OFFSET]
1058 }
1059
1060 #[inline]
1064 pub fn incompatibility_flags(&self) -> u8 {
1065 self.0[consts::v2::INCOMPAT_FLAGS_OFFSET]
1066 }
1067
1068 #[inline]
1072 pub fn incompatibility_flags_mut(&mut self) -> &mut u8 {
1073 &mut self.0[consts::v2::INCOMPAT_FLAGS_OFFSET]
1074 }
1075
1076 #[inline]
1078 pub fn compatibility_flags(&self) -> u8 {
1079 self.0[3]
1080 }
1081
1082 #[inline]
1084 pub fn sequence(&self) -> u8 {
1085 self.0[4]
1086 }
1087
1088 #[inline]
1090 pub fn system_id(&self) -> u8 {
1091 self.0[5]
1092 }
1093
1094 #[inline]
1096 pub fn component_id(&self) -> u8 {
1097 self.0[6]
1098 }
1099
1100 #[inline]
1102 pub fn message_id(&self) -> u32 {
1103 u32::from_le_bytes([self.0[7], self.0[8], self.0[9], 0])
1104 }
1105
1106 #[inline]
1108 pub fn payload(&self) -> &[u8] {
1109 let payload_length: usize = self.payload_length().into();
1110 let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1111 &self.0[payload_offset..(payload_offset + payload_length)]
1112 }
1113
1114 #[inline]
1116 pub fn checksum(&self) -> u16 {
1117 let payload_length: usize = self.payload_length().into();
1118 let checksum_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length;
1119 u16::from_le_bytes([self.0[checksum_offset], self.0[checksum_offset + 1]])
1120 }
1121
1122 #[cfg(feature = "mav2-message-signing")]
1124 #[inline]
1125 pub fn checksum_bytes(&self) -> &[u8] {
1126 let checksum_offset =
1127 consts::STX_SIZE + consts::v2::HEADER_SIZE + self.payload_length() as usize;
1128 &self.0[checksum_offset..(checksum_offset + consts::CHECKSUM_SIZE)]
1129 }
1130
1131 #[cfg(feature = "mav2-message-signing")]
1135 #[inline]
1136 pub fn signature_link_id(&self) -> u8 {
1137 let payload_length: usize = self.payload_length().into();
1138 self.0[consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE]
1139 }
1140
1141 #[cfg(feature = "mav2-message-signing")]
1143 #[inline]
1144 pub fn signature_link_id_mut(&mut self) -> &mut u8 {
1145 let payload_length: usize = self.payload_length().into();
1146 &mut self.0
1147 [consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE]
1148 }
1149
1150 #[cfg(feature = "mav2-message-signing")]
1156 #[inline]
1157 pub fn signature_timestamp(&self) -> u64 {
1158 let mut timestamp_bytes = [0u8; 8];
1159 timestamp_bytes[0..consts::v2::SIGNATURE_TIMESTAMP_SIZE]
1160 .copy_from_slice(self.signature_timestamp_bytes());
1161 u64::from_le_bytes(timestamp_bytes)
1162 }
1163
1164 #[cfg(feature = "mav2-message-signing")]
1168 #[inline]
1169 pub fn signature_timestamp_bytes(&self) -> &[u8] {
1170 let payload_length: usize = self.payload_length().into();
1171 let timestamp_start = consts::STX_SIZE
1172 + consts::v2::HEADER_SIZE
1173 + payload_length
1174 + consts::CHECKSUM_SIZE
1175 + consts::v2::SIGNATURE_LINK_ID_SIZE;
1176 &self.0[timestamp_start..(timestamp_start + consts::v2::SIGNATURE_TIMESTAMP_SIZE)]
1177 }
1178
1179 #[cfg(feature = "mav2-message-signing")]
1181 #[inline]
1182 pub fn signature_timestamp_bytes_mut(&mut self) -> &mut [u8] {
1183 let payload_length: usize = self.payload_length().into();
1184 let timestamp_start = consts::STX_SIZE
1185 + consts::v2::HEADER_SIZE
1186 + payload_length
1187 + consts::CHECKSUM_SIZE
1188 + consts::v2::SIGNATURE_LINK_ID_SIZE;
1189 &mut self.0[timestamp_start..(timestamp_start + consts::v2::SIGNATURE_TIMESTAMP_SIZE)]
1190 }
1191
1192 #[cfg(feature = "mav2-message-signing")]
1196 #[inline]
1197 pub fn signature_value(&self) -> &[u8] {
1198 let payload_length: usize = self.payload_length().into();
1199 let signature_start = consts::STX_SIZE
1200 + consts::v2::HEADER_SIZE
1201 + payload_length
1202 + consts::CHECKSUM_SIZE
1203 + consts::v2::SIGNATURE_LINK_ID_SIZE
1204 + consts::v2::SIGNATURE_TIMESTAMP_SIZE;
1205 &self.0[signature_start..(signature_start + consts::v2::SIGNATURE_VALUE_SIZE)]
1206 }
1207
1208 #[cfg(feature = "mav2-message-signing")]
1210 #[inline]
1211 pub fn signature_value_mut(&mut self) -> &mut [u8] {
1212 let payload_length: usize = self.payload_length().into();
1213 let signature_start = consts::STX_SIZE
1214 + consts::v2::HEADER_SIZE
1215 + payload_length
1216 + consts::CHECKSUM_SIZE
1217 + consts::v2::SIGNATURE_LINK_ID_SIZE
1218 + consts::v2::SIGNATURE_TIMESTAMP_SIZE;
1219 &mut self.0[signature_start..(signature_start + consts::v2::SIGNATURE_VALUE_SIZE)]
1220 }
1221
1222 fn mut_payload_and_checksum_and_sign(&mut self) -> &mut [u8] {
1223 let payload_length: usize = self.payload_length().into();
1224
1225 let signature_size = if (self.incompatibility_flags() & consts::v2::IFLAG_SIGNED) == 0 {
1227 0
1228 } else {
1229 consts::v2::SIGNATURE_SIZE
1230 };
1231
1232 let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1233 &mut self.0[payload_offset
1234 ..(payload_offset + payload_length + signature_size + consts::CHECKSUM_SIZE)]
1235 }
1236
1237 #[inline]
1239 pub fn has_valid_crc<M: Message>(&self) -> bool {
1240 let payload_length: usize = self.payload_length().into();
1241 let crc_end = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length;
1242 self.checksum()
1243 == calculate_crc(
1244 &self.0[consts::STX_SIZE..crc_end],
1245 M::extra_crc(self.message_id()),
1246 )
1247 }
1248
1249 #[cfg(feature = "mav2-message-signing")]
1253 pub fn calculate_signature(
1254 &self,
1255 secret_key: &[u8],
1256 target_buffer: &mut [u8; consts::v2::SIGNATURE_VALUE_SIZE],
1257 ) {
1258 let mut hasher = Sha256::new();
1259 hasher.update(secret_key);
1260 hasher.update([MAV_STX_V2]);
1261 hasher.update(self.header());
1262 hasher.update(self.payload());
1263 hasher.update(self.checksum_bytes());
1264 hasher.update([self.signature_link_id()]);
1265 hasher.update(self.signature_timestamp_bytes());
1266 target_buffer.copy_from_slice(&hasher.finalize()[0..consts::v2::SIGNATURE_VALUE_SIZE]);
1267 }
1268
1269 pub fn raw_bytes(&self) -> &[u8] {
1271 let payload_length = self.payload_length() as usize;
1272
1273 let signature_size = if (self.incompatibility_flags() & consts::v2::IFLAG_SIGNED) == 0 {
1274 0
1275 } else {
1276 consts::v2::SIGNATURE_SIZE
1277 };
1278
1279 let frame_len = consts::STX_SIZE
1280 + consts::v2::HEADER_SIZE
1281 + payload_length
1282 + signature_size
1283 + consts::CHECKSUM_SIZE;
1284 &self.0[..frame_len]
1285 }
1286
1287 fn serialize_stx_and_header_and_crc(
1288 &mut self,
1289 header: MavHeader,
1290 msgid: u32,
1291 payload_length: usize,
1292 extra_crc: u8,
1293 incompat_flags: u8,
1294 ) {
1295 self.0[consts::STX_OFFSET] = MAV_STX_V2;
1296 let msgid_bytes = msgid.to_le_bytes();
1297
1298 let header_buf = self.mut_header();
1299 header_buf.copy_from_slice(&[
1300 payload_length as u8,
1301 incompat_flags,
1302 0, header.sequence,
1304 header.system_id,
1305 header.component_id,
1306 msgid_bytes[0],
1307 msgid_bytes[1],
1308 msgid_bytes[2],
1309 ]);
1310
1311 let crc = calculate_crc(
1312 &self.0
1313 [consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length)],
1314 extra_crc,
1315 );
1316 self.0[(consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length)
1317 ..(consts::STX_SIZE
1318 + consts::v2::HEADER_SIZE
1319 + payload_length
1320 + consts::CHECKSUM_SIZE)]
1321 .copy_from_slice(&crc.to_le_bytes());
1322 }
1323
1324 pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
1328 let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1329 let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
1330 let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
1331
1332 let message_id = message.message_id();
1333 self.serialize_stx_and_header_and_crc(
1334 header,
1335 message_id,
1336 payload_length,
1337 M::extra_crc(message_id),
1338 0,
1339 );
1340 }
1341
1342 pub fn serialize_message_for_signing<M: Message>(&mut self, header: MavHeader, message: &M) {
1347 let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1348 let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
1349 let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
1350
1351 let message_id = message.message_id();
1352 self.serialize_stx_and_header_and_crc(
1353 header,
1354 message_id,
1355 payload_length,
1356 M::extra_crc(message_id),
1357 consts::v2::IFLAG_SIGNED,
1358 );
1359 }
1360
1361 pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
1362 let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1363 let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
1364 let payload_length = message_data.ser(MavlinkVersion::V2, payload_buf);
1365
1366 self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC, 0);
1367 }
1368}
1369
1370#[allow(unused_variables)]
1371fn try_decode_v2<M: Message, R: Read>(
1372 reader: &mut PeekReader<R>,
1373 signing_data: Option<&SigningData>,
1374) -> Result<Option<MAVLinkV2MessageRaw>, MessageReadError> {
1375 let mut message = MAVLinkV2MessageRaw::new();
1376 let whole_header_size = consts::STX_SIZE + consts::v2::HEADER_SIZE;
1377
1378 message.0[consts::STX_OFFSET] = MAV_STX_V2;
1379 let header = &reader.peek_exact(whole_header_size)?[consts::STX_SIZE..whole_header_size];
1380 message.mut_header().copy_from_slice(header);
1381
1382 if message.incompatibility_flags() & !consts::v2::SUPPORTED_IFLAGS > 0 {
1383 reader.consume(consts::STX_SIZE);
1385 return Ok(None);
1386 }
1387
1388 let packet_length = message.raw_bytes().len();
1389 let payload_and_checksum_and_sign =
1390 &reader.peek_exact(packet_length)?[whole_header_size..packet_length];
1391 message
1392 .mut_payload_and_checksum_and_sign()
1393 .copy_from_slice(payload_and_checksum_and_sign);
1394
1395 if message.has_valid_crc::<M>() {
1396 reader.consume(message.raw_bytes().len());
1398 } else {
1399 reader.consume(consts::STX_SIZE);
1400 return Ok(None);
1401 }
1402
1403 #[cfg(feature = "mav2-message-signing")]
1404 if let Some(signing_data) = signing_data {
1405 if !signing_data.verify_signature(&message) {
1406 return Ok(None);
1407 }
1408 }
1409
1410 Ok(Some(message))
1411}
1412
1413#[cfg(feature = "tokio")]
1414#[allow(unused_variables)]
1415async fn try_decode_v2_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1417 reader: &mut AsyncPeekReader<R>,
1418 signing_data: Option<&SigningData>,
1419) -> Result<Option<MAVLinkV2MessageRaw>, MessageReadError> {
1420 let mut message = MAVLinkV2MessageRaw::new();
1421
1422 message.0[consts::STX_OFFSET] = MAV_STX_V2;
1423 let header = &reader.peek_exact(consts::v2::HEADER_SIZE).await?[..consts::v2::HEADER_SIZE];
1424 message.mut_header().copy_from_slice(header);
1425
1426 if message.incompatibility_flags() & !consts::v2::SUPPORTED_IFLAGS > 0 {
1427 return Ok(None);
1429 }
1430
1431 let packet_length = message.raw_bytes().len() - consts::STX_SIZE;
1432 let payload_and_checksum_and_sign =
1433 &reader.peek_exact(packet_length).await?[consts::v2::HEADER_SIZE..packet_length];
1434 message
1435 .mut_payload_and_checksum_and_sign()
1436 .copy_from_slice(payload_and_checksum_and_sign);
1437
1438 if message.has_valid_crc::<M>() {
1439 reader.consume(message.raw_bytes().len() - consts::STX_SIZE);
1441 } else {
1442 return Ok(None);
1443 }
1444
1445 #[cfg(feature = "mav2-message-signing")]
1446 if let Some(signing_data) = signing_data {
1447 if !signing_data.verify_signature(&message) {
1448 return Ok(None);
1449 }
1450 }
1451
1452 Ok(Some(message))
1453}
1454
1455#[inline]
1461pub fn read_v2_raw_message<M: Message, R: Read>(
1462 reader: &mut PeekReader<R>,
1463) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1464 read_v2_raw_message_inner::<M, R>(reader, None)
1465}
1466
1467#[cfg(feature = "mav2-message-signing")]
1473#[inline]
1474pub fn read_v2_raw_message_signed<M: Message, R: Read>(
1475 reader: &mut PeekReader<R>,
1476 signing_data: Option<&SigningData>,
1477) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1478 read_v2_raw_message_inner::<M, R>(reader, signing_data)
1479}
1480
1481#[allow(unused_variables)]
1482fn read_v2_raw_message_inner<M: Message, R: Read>(
1483 reader: &mut PeekReader<R>,
1484 signing_data: Option<&SigningData>,
1485) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1486 loop {
1487 while reader.peek_exact(consts::STX_SIZE)?[consts::STX_OFFSET] != MAV_STX_V2 {
1489 reader.consume(consts::STX_SIZE);
1490 }
1491
1492 if let Some(message) = try_decode_v2::<M, _>(reader, signing_data)? {
1493 return Ok(message);
1494 }
1495 }
1496}
1497
1498#[cfg(feature = "tokio")]
1504pub async fn read_v2_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1505 reader: &mut AsyncPeekReader<R>,
1506) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1507 read_v2_raw_message_async_inner::<M, R>(reader, None).await
1508}
1509
1510#[cfg(feature = "tokio")]
1511#[allow(unused_variables)]
1512async fn read_v2_raw_message_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1513 reader: &mut AsyncPeekReader<R>,
1514 signing_data: Option<&SigningData>,
1515) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1516 loop {
1517 loop {
1518 if reader.read_u8().await? == MAV_STX_V2 {
1520 break;
1521 }
1522 }
1523
1524 if let Some(message) = try_decode_v2_async::<M, _>(reader, signing_data).await? {
1525 return Ok(message);
1526 }
1527 }
1528}
1529
1530#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
1536pub async fn read_v2_raw_message_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1537 reader: &mut AsyncPeekReader<R>,
1538 signing_data: Option<&SigningData>,
1539) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1540 read_v2_raw_message_async_inner::<M, R>(reader, signing_data).await
1541}
1542
1543#[cfg(all(feature = "embedded", not(feature = "std")))]
1549pub async fn read_v2_raw_message_async<M: Message>(
1550 reader: &mut impl embedded_io_async::Read,
1551) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1552 loop {
1553 let mut byte = [0u8; consts::STX_SIZE];
1555 loop {
1556 reader
1557 .read_exact(&mut byte)
1558 .await
1559 .map_err(|_| MessageReadError::Io)?;
1560 if byte[consts::STX_OFFSET] == MAV_STX_V2 {
1561 break;
1562 }
1563 }
1564
1565 let mut message = MAVLinkV2MessageRaw::new();
1566
1567 message.0[consts::STX_OFFSET] = MAV_STX_V2;
1568 reader
1569 .read_exact(message.mut_header())
1570 .await
1571 .map_err(|_| MessageReadError::Io)?;
1572
1573 if message.incompatibility_flags() & !consts::v2::SUPPORTED_IFLAGS > 0 {
1574 continue;
1576 }
1577
1578 reader
1579 .read_exact(message.mut_payload_and_checksum_and_sign())
1580 .await
1581 .map_err(|_| MessageReadError::Io)?;
1582
1583 if message.has_valid_crc::<M>() {
1586 return Ok(message);
1587 }
1588 }
1589}
1590
1591#[inline]
1597pub fn read_v2_msg<M: Message, R: Read>(
1598 read: &mut PeekReader<R>,
1599) -> Result<(MavHeader, M), MessageReadError> {
1600 read_v2_msg_inner(read, None)
1601}
1602
1603#[cfg(feature = "mav2-message-signing")]
1609#[inline]
1610pub fn read_v2_msg_signed<M: Message, R: Read>(
1611 read: &mut PeekReader<R>,
1612 signing_data: Option<&SigningData>,
1613) -> Result<(MavHeader, M), MessageReadError> {
1614 read_v2_msg_inner(read, signing_data)
1615}
1616
1617fn read_v2_msg_inner<M: Message, R: Read>(
1618 read: &mut PeekReader<R>,
1619 signing_data: Option<&SigningData>,
1620) -> Result<(MavHeader, M), MessageReadError> {
1621 let message = read_v2_raw_message_inner::<M, _>(read, signing_data)?;
1622
1623 Ok((
1624 MavHeader {
1625 sequence: message.sequence(),
1626 system_id: message.system_id(),
1627 component_id: message.component_id(),
1628 },
1629 M::parse(MavlinkVersion::V2, message.message_id(), message.payload())?,
1630 ))
1631}
1632
1633#[cfg(feature = "tokio")]
1639pub async fn read_v2_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1640 read: &mut AsyncPeekReader<R>,
1641) -> Result<(MavHeader, M), MessageReadError> {
1642 read_v2_msg_async_inner(read, None).await
1643}
1644
1645#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
1651pub async fn read_v2_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1652 read: &mut AsyncPeekReader<R>,
1653 signing_data: Option<&SigningData>,
1654) -> Result<(MavHeader, M), MessageReadError> {
1655 read_v2_msg_async_inner(read, signing_data).await
1656}
1657
1658#[cfg(feature = "tokio")]
1659async fn read_v2_msg_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1660 read: &mut AsyncPeekReader<R>,
1661 signing_data: Option<&SigningData>,
1662) -> Result<(MavHeader, M), MessageReadError> {
1663 let message = read_v2_raw_message_async_inner::<M, _>(read, signing_data).await?;
1664
1665 Ok((
1666 MavHeader {
1667 sequence: message.sequence(),
1668 system_id: message.system_id(),
1669 component_id: message.component_id(),
1670 },
1671 M::parse(MavlinkVersion::V2, message.message_id(), message.payload())?,
1672 ))
1673}
1674
1675#[cfg(all(feature = "embedded", not(feature = "std")))]
1680pub async fn read_v2_msg_async<M: Message, R: embedded_io_async::Read>(
1681 r: &mut R,
1682) -> Result<(MavHeader, M), MessageReadError> {
1683 let message = read_v2_raw_message_async::<M>(r).await?;
1684
1685 Ok((
1686 MavHeader {
1687 sequence: message.sequence(),
1688 system_id: message.system_id(),
1689 component_id: message.component_id(),
1690 },
1691 M::parse(
1692 MavlinkVersion::V2,
1693 u32::from(message.message_id()),
1694 message.payload(),
1695 )?,
1696 ))
1697}
1698
1699pub enum MAVLinkMessageRaw {
1701 V1(MAVLinkV1MessageRaw),
1702 V2(MAVLinkV2MessageRaw),
1703}
1704
1705impl MAVLinkMessageRaw {
1706 pub fn payload(&self) -> &[u8] {
1707 match self {
1708 Self::V1(msg) => msg.payload(),
1709 Self::V2(msg) => msg.payload(),
1710 }
1711 }
1712 pub fn sequence(&self) -> u8 {
1713 match self {
1714 Self::V1(msg) => msg.sequence(),
1715 Self::V2(msg) => msg.sequence(),
1716 }
1717 }
1718 pub fn system_id(&self) -> u8 {
1719 match self {
1720 Self::V1(msg) => msg.system_id(),
1721 Self::V2(msg) => msg.system_id(),
1722 }
1723 }
1724 pub fn component_id(&self) -> u8 {
1725 match self {
1726 Self::V1(msg) => msg.component_id(),
1727 Self::V2(msg) => msg.component_id(),
1728 }
1729 }
1730 pub fn message_id(&self) -> u32 {
1731 match self {
1732 Self::V1(msg) => u32::from(msg.message_id()),
1733 Self::V2(msg) => msg.message_id(),
1734 }
1735 }
1736 pub fn version(&self) -> MavlinkVersion {
1737 match self {
1738 Self::V1(_) => MavlinkVersion::V1,
1739 Self::V2(_) => MavlinkVersion::V2,
1740 }
1741 }
1742}
1743
1744#[inline]
1750pub fn read_any_raw_message<M: Message, R: Read>(
1751 reader: &mut PeekReader<R>,
1752) -> Result<MAVLinkMessageRaw, MessageReadError> {
1753 read_any_raw_message_inner::<M, R>(reader, None)
1754}
1755
1756#[cfg(feature = "mav2-message-signing")]
1762#[inline]
1763pub fn read_any_raw_message_signed<M: Message, R: Read>(
1764 reader: &mut PeekReader<R>,
1765 signing_data: Option<&SigningData>,
1766) -> Result<MAVLinkMessageRaw, MessageReadError> {
1767 read_any_raw_message_inner::<M, R>(reader, signing_data)
1768}
1769
1770#[allow(unused_variables)]
1771fn read_any_raw_message_inner<M: Message, R: Read>(
1772 reader: &mut PeekReader<R>,
1773 signing_data: Option<&SigningData>,
1774) -> Result<MAVLinkMessageRaw, MessageReadError> {
1775 loop {
1776 let version = loop {
1778 let byte = reader.peek_exact(consts::STX_SIZE)?[consts::STX_OFFSET];
1779 if byte == MAV_STX {
1780 break MavlinkVersion::V1;
1781 }
1782 if byte == MAV_STX_V2 {
1783 break MavlinkVersion::V2;
1784 }
1785 reader.consume(consts::STX_SIZE);
1786 };
1787 match version {
1788 MavlinkVersion::V1 => {
1789 if let Some(message) = try_decode_v1::<M, _>(reader)? {
1790 #[cfg(feature = "mav2-message-signing")]
1792 if let Some(signing) = signing_data {
1793 if signing.config.allow_unsigned {
1794 return Ok(MAVLinkMessageRaw::V1(message));
1795 }
1796 } else {
1797 return Ok(MAVLinkMessageRaw::V1(message));
1798 }
1799 #[cfg(not(feature = "mav2-message-signing"))]
1800 return Ok(MAVLinkMessageRaw::V1(message));
1801 }
1802
1803 reader.consume(consts::STX_SIZE);
1804 }
1805 MavlinkVersion::V2 => {
1806 if let Some(message) = try_decode_v2::<M, _>(reader, signing_data)? {
1807 return Ok(MAVLinkMessageRaw::V2(message));
1808 }
1809 }
1810 }
1811 }
1812}
1813
1814#[cfg(feature = "tokio")]
1820pub async fn read_any_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1821 reader: &mut AsyncPeekReader<R>,
1822) -> Result<MAVLinkMessageRaw, MessageReadError> {
1823 read_any_raw_message_async_inner::<M, R>(reader, None).await
1824}
1825
1826#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
1834pub async fn read_any_raw_message_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1835 reader: &mut AsyncPeekReader<R>,
1836 signing_data: Option<&SigningData>,
1837) -> Result<MAVLinkMessageRaw, MessageReadError> {
1838 read_any_raw_message_async_inner::<M, R>(reader, signing_data).await
1839}
1840
1841#[cfg(feature = "tokio")]
1842#[allow(unused_variables)]
1843async fn read_any_raw_message_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1844 reader: &mut AsyncPeekReader<R>,
1845 signing_data: Option<&SigningData>,
1846) -> Result<MAVLinkMessageRaw, MessageReadError> {
1847 loop {
1848 let version = loop {
1850 let read = reader.read_u8().await?;
1851 if read == MAV_STX {
1852 break MavlinkVersion::V1;
1853 }
1854 if read == MAV_STX_V2 {
1855 break MavlinkVersion::V2;
1856 }
1857 };
1858
1859 match version {
1860 MavlinkVersion::V1 => {
1861 if let Some(message) = try_decode_v1_async::<M, _>(reader).await? {
1862 #[cfg(feature = "mav2-message-signing")]
1864 if let Some(signing) = signing_data {
1865 if signing.config.allow_unsigned {
1866 return Ok(MAVLinkMessageRaw::V1(message));
1867 }
1868 } else {
1869 return Ok(MAVLinkMessageRaw::V1(message));
1870 }
1871 #[cfg(not(feature = "mav2-message-signing"))]
1872 return Ok(MAVLinkMessageRaw::V1(message));
1873 }
1874 }
1875 MavlinkVersion::V2 => {
1876 if let Some(message) = try_decode_v2_async::<M, _>(reader, signing_data).await? {
1877 return Ok(MAVLinkMessageRaw::V2(message));
1878 }
1879 }
1880 }
1881 }
1882}
1883
1884#[inline]
1890pub fn read_any_msg<M: Message, R: Read>(
1891 read: &mut PeekReader<R>,
1892) -> Result<(MavHeader, M), MessageReadError> {
1893 read_any_msg_inner(read, None)
1894}
1895
1896#[cfg(feature = "mav2-message-signing")]
1904#[inline]
1905pub fn read_any_msg_signed<M: Message, R: Read>(
1906 read: &mut PeekReader<R>,
1907 signing_data: Option<&SigningData>,
1908) -> Result<(MavHeader, M), MessageReadError> {
1909 read_any_msg_inner(read, signing_data)
1910}
1911
1912fn read_any_msg_inner<M: Message, R: Read>(
1913 read: &mut PeekReader<R>,
1914 signing_data: Option<&SigningData>,
1915) -> Result<(MavHeader, M), MessageReadError> {
1916 let message = read_any_raw_message_inner::<M, _>(read, signing_data)?;
1917 Ok((
1918 MavHeader {
1919 sequence: message.sequence(),
1920 system_id: message.system_id(),
1921 component_id: message.component_id(),
1922 },
1923 M::parse(message.version(), message.message_id(), message.payload())?,
1924 ))
1925}
1926
1927#[cfg(feature = "tokio")]
1933pub async fn read_any_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1934 read: &mut AsyncPeekReader<R>,
1935) -> Result<(MavHeader, M), MessageReadError> {
1936 read_any_msg_async_inner(read, None).await
1937}
1938
1939#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
1947#[inline]
1948pub async fn read_any_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1949 read: &mut AsyncPeekReader<R>,
1950 signing_data: Option<&SigningData>,
1951) -> Result<(MavHeader, M), MessageReadError> {
1952 read_any_msg_async_inner(read, signing_data).await
1953}
1954
1955#[cfg(feature = "tokio")]
1956async fn read_any_msg_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1957 read: &mut AsyncPeekReader<R>,
1958 signing_data: Option<&SigningData>,
1959) -> Result<(MavHeader, M), MessageReadError> {
1960 let message = read_any_raw_message_async_inner::<M, _>(read, signing_data).await?;
1961
1962 Ok((
1963 MavHeader {
1964 sequence: message.sequence(),
1965 system_id: message.system_id(),
1966 component_id: message.component_id(),
1967 },
1968 M::parse(message.version(), message.message_id(), message.payload())?,
1969 ))
1970}
1971
1972pub fn write_versioned_msg<M: Message, W: Write>(
1978 w: &mut W,
1979 version: MavlinkVersion,
1980 header: MavHeader,
1981 data: &M,
1982) -> Result<usize, MessageWriteError> {
1983 match version {
1984 MavlinkVersion::V2 => write_v2_msg(w, header, data),
1985 MavlinkVersion::V1 => write_v1_msg(w, header, data),
1986 }
1987}
1988
1989#[cfg(feature = "mav2-message-signing")]
1997pub fn write_versioned_msg_signed<M: Message, W: Write>(
1998 w: &mut W,
1999 version: MavlinkVersion,
2000 header: MavHeader,
2001 data: &M,
2002 signing_data: Option<&SigningData>,
2003) -> Result<usize, MessageWriteError> {
2004 match version {
2005 MavlinkVersion::V2 => write_v2_msg_signed(w, header, data, signing_data),
2006 MavlinkVersion::V1 => write_v1_msg(w, header, data),
2007 }
2008}
2009
2010#[cfg(feature = "tokio")]
2016pub async fn write_versioned_msg_async<M: Message, W: AsyncWrite + Unpin>(
2017 w: &mut W,
2018 version: MavlinkVersion,
2019 header: MavHeader,
2020 data: &M,
2021) -> Result<usize, MessageWriteError> {
2022 match version {
2023 MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
2024 MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2025 }
2026}
2027
2028#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
2036pub async fn write_versioned_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
2037 w: &mut W,
2038 version: MavlinkVersion,
2039 header: MavHeader,
2040 data: &M,
2041 signing_data: Option<&SigningData>,
2042) -> Result<usize, MessageWriteError> {
2043 match version {
2044 MavlinkVersion::V2 => write_v2_msg_async_signed(w, header, data, signing_data).await,
2045 MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2046 }
2047}
2048
2049#[cfg(all(feature = "embedded", not(feature = "std")))]
2054pub async fn write_versioned_msg_async<M: Message>(
2055 w: &mut impl embedded_io_async::Write,
2056 version: MavlinkVersion,
2057 header: MavHeader,
2058 data: &M,
2059) -> Result<usize, MessageWriteError> {
2060 match version {
2061 MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
2062 MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2063 }
2064}
2065
2066pub fn write_v2_msg<M: Message, W: Write>(
2072 w: &mut W,
2073 header: MavHeader,
2074 data: &M,
2075) -> Result<usize, MessageWriteError> {
2076 let mut message_raw = MAVLinkV2MessageRaw::new();
2077 message_raw.serialize_message(header, data);
2078
2079 let payload_length: usize = message_raw.payload_length().into();
2080 let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2081
2082 w.write_all(&message_raw.0[..len])?;
2083
2084 Ok(len)
2085}
2086
2087#[cfg(feature = "mav2-message-signing")]
2093pub fn write_v2_msg_signed<M: Message, W: Write>(
2094 w: &mut W,
2095 header: MavHeader,
2096 data: &M,
2097 signing_data: Option<&SigningData>,
2098) -> Result<usize, MessageWriteError> {
2099 let mut message_raw = MAVLinkV2MessageRaw::new();
2100
2101 let signature_len = if let Some(signing_data) = signing_data {
2102 if signing_data.config.sign_outgoing {
2103 message_raw.serialize_message_for_signing(header, data);
2104 signing_data.sign_message(&mut message_raw);
2105 consts::v2::SIGNATURE_SIZE
2106 } else {
2107 message_raw.serialize_message(header, data);
2108 0
2109 }
2110 } else {
2111 message_raw.serialize_message(header, data);
2112 0
2113 };
2114
2115 let payload_length: usize = message_raw.payload_length().into();
2116 let len = consts::STX_SIZE
2117 + consts::v2::HEADER_SIZE
2118 + payload_length
2119 + consts::CHECKSUM_SIZE
2120 + signature_len;
2121
2122 w.write_all(&message_raw.0[..len])?;
2123
2124 Ok(len)
2125}
2126
2127#[cfg(feature = "tokio")]
2133pub async fn write_v2_msg_async<M: Message, W: AsyncWrite + Unpin>(
2134 w: &mut W,
2135 header: MavHeader,
2136 data: &M,
2137) -> Result<usize, MessageWriteError> {
2138 let mut message_raw = MAVLinkV2MessageRaw::new();
2139 message_raw.serialize_message(header, data);
2140
2141 let payload_length: usize = message_raw.payload_length().into();
2142 let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2143
2144 w.write_all(&message_raw.0[..len]).await?;
2145
2146 Ok(len)
2147}
2148
2149#[cfg(feature = "mav2-message-signing")]
2155#[cfg(feature = "tokio")]
2156pub async fn write_v2_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
2157 w: &mut W,
2158 header: MavHeader,
2159 data: &M,
2160 signing_data: Option<&SigningData>,
2161) -> Result<usize, MessageWriteError> {
2162 let mut message_raw = MAVLinkV2MessageRaw::new();
2163
2164 let signature_len = if let Some(signing_data) = signing_data {
2165 if signing_data.config.sign_outgoing {
2166 message_raw.serialize_message_for_signing(header, data);
2167 signing_data.sign_message(&mut message_raw);
2168 consts::v2::SIGNATURE_SIZE
2169 } else {
2170 message_raw.serialize_message(header, data);
2171 0
2172 }
2173 } else {
2174 message_raw.serialize_message(header, data);
2175 0
2176 };
2177
2178 let payload_length: usize = message_raw.payload_length().into();
2179 let len = consts::STX_SIZE
2180 + consts::v2::HEADER_SIZE
2181 + payload_length
2182 + consts::CHECKSUM_SIZE
2183 + signature_len;
2184
2185 w.write_all(&message_raw.0[..len]).await?;
2186
2187 Ok(len)
2188}
2189
2190#[cfg(all(feature = "embedded", not(feature = "std")))]
2199pub async fn write_v2_msg_async<M: Message>(
2200 w: &mut impl embedded_io_async::Write,
2201 header: MavHeader,
2202 data: &M,
2203) -> Result<usize, MessageWriteError> {
2204 let mut message_raw = MAVLinkV2MessageRaw::new();
2205 message_raw.serialize_message(header, data);
2206
2207 let payload_length: usize = message_raw.payload_length().into();
2208 let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2209
2210 w.write_all(&message_raw.0[..len])
2211 .await
2212 .map_err(|_| MessageWriteError::Io)?;
2213
2214 Ok(len)
2215}
2216
2217pub fn write_v1_msg<M: Message, W: Write>(
2223 w: &mut W,
2224 header: MavHeader,
2225 data: &M,
2226) -> Result<usize, MessageWriteError> {
2227 if data.message_id() > u8::MAX.into() {
2228 return Err(MessageWriteError::MAVLink2Only);
2229 }
2230 let mut message_raw = MAVLinkV1MessageRaw::new();
2231 message_raw.serialize_message(header, data);
2232
2233 let payload_length: usize = message_raw.payload_length().into();
2234 let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2235
2236 w.write_all(&message_raw.0[..len])?;
2237
2238 Ok(len)
2239}
2240
2241#[cfg(feature = "tokio")]
2247pub async fn write_v1_msg_async<M: Message, W: AsyncWrite + Unpin>(
2248 w: &mut W,
2249 header: MavHeader,
2250 data: &M,
2251) -> Result<usize, MessageWriteError> {
2252 if data.message_id() > u8::MAX.into() {
2253 return Err(MessageWriteError::MAVLink2Only);
2254 }
2255 let mut message_raw = MAVLinkV1MessageRaw::new();
2256 message_raw.serialize_message(header, data);
2257
2258 let payload_length: usize = message_raw.payload_length().into();
2259 let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2260
2261 w.write_all(&message_raw.0[..len]).await?;
2262
2263 Ok(len)
2264}
2265
2266#[cfg(all(feature = "embedded", not(feature = "std")))]
2271pub async fn write_v1_msg_async<M: Message>(
2272 w: &mut impl embedded_io_async::Write,
2273 header: MavHeader,
2274 data: &M,
2275) -> Result<usize, MessageWriteError> {
2276 if data.message_id() > u8::MAX.into() {
2277 return Err(MessageWriteError::MAVLink2Only);
2278 }
2279 let mut message_raw = MAVLinkV1MessageRaw::new();
2280 message_raw.serialize_message(header, data);
2281
2282 let payload_length: usize = message_raw.payload_length().into();
2283 let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
2284
2285 w.write_all(&message_raw.0[..len])
2286 .await
2287 .map_err(|_| MessageWriteError::Io)?;
2288
2289 Ok(len)
2290}