mavlink_core/
lib.rs

1//! The MAVLink message set.
2//!
3//! # Message sets and the `Message` trait
4//! Each message set has its own module with corresponding data types, including a `MavMessage` enum
5//! that represents all possible messages in that message set. The [`Message`] trait is used to
6//! represent messages in an abstract way, and each `MavMessage` enum implements this trait (for
7//! example, [ardupilotmega::MavMessage]). This is then monomorphized to the specific message
8//! set you are using in your application at compile-time via type parameters. If you expect
9//! ArduPilotMega-flavored messages, then you will need a `MavConnection<ardupilotmega::MavMessage>`
10//! and you will receive `ardupilotmega::MavMessage`s from it.
11//!
12//! Some message sets include others. For example, most message sets include the
13//! common message set. These included values are not differently represented in the `MavMessage` enum: a message
14//! in the common message set received on an ArduPilotMega connection will just be an
15//! `ardupilotmega::MavMessage`.
16//!
17//! If you want to enable a given message set, you do not have to enable the
18//! feature for the message sets that it includes. For example, you can use the `ardupilotmega`
19//! feature without also using the `uavionix`, `icarous`, `common` features.
20//!
21//! [ardupilotmega::MavMessage]: https://docs.rs/mavlink/latest/mavlink/ardupilotmega/enum.MavMessage.html
22//!
23//! # Read Functions
24//!
25//! The `read_*` functions can be used to read a MAVLink message for a [`PeekReader`] wrapping a `[Read]`er.
26//!
27//! They follow the pattern `read_(v1|v2|any|versioned)_(raw_message|msg)[_async][_signed]<M, _>(..)`.
28//! All read functions check for a valid `STX` marker of the corresponding MAVLink version and verify that the message CRC checksum is correct.
29//! They attempt to read until either a whole MAVLink message is read or an error occurrs.
30//! While doing so data without STX marker, with an invalid CRC chechsum or invalid signature (if applicable) is discarded.
31//! To determine for which dialect the message CRC should be verified it must be specified
32//! by using the `Message` enum of the dialect as the generic `M`.
33//!
34//! Unless further specified all combinations of the function name components exist. The components are described bellow:
35//!
36//! - `v1` functions read only MAVLink 1 messages
37//! - `v2` functions read only MAVLink 2 messages
38//! - `any` functions read messages of either MAVLink version
39//! - `versioned` functions read messages of the version specified in an aditional `version` parameter
40//! - `raw_message` functions return an unparsed message as [`MAVLinkV1MessageRaw`], [`MAVLinkV2MessageRaw`] or [`MAVLinkMessageRaw`]
41//! - `msg` functions return a parsed message as a tupel of [`MavHeader`] and the `Message` of the specified dialect
42//! - `_async` functions, which are only enabled with the `tokio-1` feature, are [async](https://doc.rust-lang.org/std/keyword.async.html) and read from an [`AsyncPeekReader`] instead.
43//! - `_signed` functions, which are only enabled with the `signing` feature, have an `Option<&SigningData>` parameter that allows the use of MAVLink 2 message signing.
44//!   MAVLink 1 exclusive functions do not have a `_signed` variant and functions that allow both MAVLink 1 and 2 messages treat MAVLink 1 messages as unsigned.
45//!   When an invalidly signed message is received it is ignored.
46//!
47//! ## Read Errors
48//! All `read_` functions return `Result<_,` [`MessageReadError`]`>`.
49//!
50//! - All functions will return [`MessageReadError::Io`] of [`UnexpectedEof`] when EOF is encountered before a message could be read.
51//! - All functions will return [`MessageReadError::Io`] when an error occurs on the underlying [`Read`]er or [`AsyncRead`]er.
52//!   
53//! - Functions that parse the received message will return [`MessageReadError::Parse`] when the read data could
54//!   not be parsed as a MAVLink message
55//!
56//! # Write Functions
57//!
58//! The `write_` functions are used to write a MAVLink to a [`Write`]r.
59//! They follow the pattern `write_(v1|v2|versioned)_msg[_async][_signed](..)`:
60//!
61//! - `v1` functions write messages using MAVLink 1 serialisation
62//! - `v2` functions write messages using MAVLink 2 serialisation
63//! - `versioned` functions write messages using the version specified in an aditional `version` parameter
64//! - `_async` functions, which are only enabled with the `tokio-1` feature, are
65//!   [async](https://doc.rust-lang.org/std/keyword.async.html) and write from an [`tokio::io::AsyncWrite`]r instead.
66//! - `_signed` functions, which are only enabled with the `signing` feature, have an `Option<&SigningData>` parameter that allows the use of MAVLink 2 message signing.
67//!
68//! ## Write errors
69//!
70//! All `write_` functions return `Result<_,` [`MessageWriteError`]`>`.
71//!
72//! - When an error occurs on the underlying [`Write`]er or [`AsyncWrite`]er other then
73//!   [`Interrupted`] the function returns [`MessageWriteError::Io`]
74//! - When attempting to serialize a message with an ID over 255 with MAVLink 1 a [`MessageWriteError::MAVLink2Only`] is returned
75//!
76//! [`PeekReader`]: peek_reader::PeekReader
77//! [`AsyncPeekReader`]: async_peek_reader::AsyncPeekReader
78//! [`UnexpectedEof`]: std::io::ErrorKind::UnexpectedEof
79//! [`AsyncRead`]: tokio::io::AsyncRead
80//! [`AsyncWrite`]: tokio::io::AsyncWrite
81//! [`Interrupted`]: std::io::ErrorKind::Interrupted
82#![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::{remove_trailing_zeroes, RustDefault};
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(feature = "std")]
114mod connection;
115pub mod error;
116pub mod types;
117#[cfg(feature = "std")]
118pub use self::connection::{connect, Connectable, MavConnection};
119
120#[cfg(feature = "tokio-1")]
121mod async_connection;
122#[cfg(feature = "tokio-1")]
123pub use self::async_connection::{connect_async, AsyncConnectable, AsyncMavConnection};
124
125#[cfg(feature = "tokio-1")]
126pub mod async_peek_reader;
127#[cfg(feature = "tokio-1")]
128use async_peek_reader::AsyncPeekReader;
129#[cfg(feature = "tokio-1")]
130use tokio::io::{AsyncWrite, AsyncWriteExt};
131
132#[cfg(any(feature = "embedded", feature = "embedded-hal-02"))]
133pub mod embedded;
134#[cfg(any(feature = "embedded", feature = "embedded-hal-02"))]
135use embedded::{Read, Write};
136
137#[cfg(not(feature = "signing"))]
138type SigningData = ();
139#[cfg(feature = "signing")]
140mod signing;
141#[cfg(feature = "signing")]
142pub use self::signing::{SigningConfig, SigningData};
143#[cfg(feature = "signing")]
144use sha2::{Digest, Sha256};
145
146#[cfg(feature = "arbitrary")]
147use arbitrary::Arbitrary;
148
149#[cfg(any(feature = "std", feature = "tokio-1"))]
150mod connectable;
151
152#[cfg(any(feature = "std", feature = "tokio-1"))]
153pub use connectable::ConnectionAddress;
154
155#[cfg(feature = "direct-serial")]
156pub use connection::direct_serial::config::SerialConfig;
157
158#[cfg(feature = "tcp")]
159pub use connection::tcp::config::{TcpConfig, TcpMode};
160
161#[cfg(feature = "udp")]
162pub use connection::udp::config::{UdpConfig, UdpMode};
163
164#[cfg(feature = "std")]
165pub use connection::file::config::FileConfig;
166
167/// Maximum size of any MAVLink frame in bytes.
168///
169/// This is a v2 frame with maximum payload size and a signature: <https://mavlink.io/en/guide/serialization.html>
170pub const MAX_FRAME_SIZE: usize = 280;
171
172/// A MAVLink message payload
173///
174/// Each message sets `MavMessage` enum implements this trait. The [`Message`] trait is used to
175/// represent messages in an abstract way (for example, `common::MavMessage`).
176pub trait Message
177where
178    Self: Sized,
179{
180    /// MAVLink message ID
181    fn message_id(&self) -> u32;
182
183    /// MAVLink message name
184    fn message_name(&self) -> &'static str;
185
186    /// Target system ID if the message is directed to a specific system
187    fn target_system_id(&self) -> Option<u8>;
188
189    /// Target component ID if the message is directed to a specific component
190    fn target_component_id(&self) -> Option<u8>;
191
192    /// Serialize **Message** into byte slice and return count of bytes written
193    ///
194    /// # Panics
195    ///
196    /// Will panic if the buffer provided is to small to store this message
197    fn ser(&self, version: MavlinkVersion, bytes: &mut [u8]) -> usize;
198
199    /// Parse a Message from its message id and payload bytes
200    ///
201    /// # Errors
202    ///
203    /// - [`UnknownMessage`] if the given message id is not part of the dialect
204    /// - any other [`ParserError`] returned by the individual message deserialization
205    ///
206    /// [`UnknownMessage`]: ParserError::UnknownMessage
207    fn parse(version: MavlinkVersion, msgid: u32, payload: &[u8]) -> Result<Self, ParserError>;
208
209    /// Return message id of specific message name
210    fn message_id_from_name(name: &str) -> Option<u32>;
211    /// Return a default message of the speicfied message id
212    fn default_message_from_id(id: u32) -> Option<Self>;
213    /// Return random valid message of the speicfied message id
214    #[cfg(feature = "arbitrary")]
215    fn random_message_from_id<R: rand::RngCore>(id: u32, rng: &mut R) -> Option<Self>;
216    /// Return a message types [CRC_EXTRA byte](https://mavlink.io/en/guide/serialization.html#crc_extra)
217    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    /// # Panics
229    ///
230    /// Will panic if the buffer provided is to small to hold the full message payload of the implementing message type
231    fn ser(&self, version: MavlinkVersion, payload: &mut [u8]) -> usize;
232    /// # Errors
233    ///
234    /// Will return [`ParserError::InvalidEnum`] on a nonexistent enum value and
235    /// [`ParserError::InvalidFlag`] on an invalid bitflag value
236    fn deser(version: MavlinkVersion, payload: &[u8]) -> Result<Self, ParserError>;
237}
238
239/// Metadata from a MAVLink packet header
240#[derive(Debug, Copy, Clone, PartialEq, Eq)]
241#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
242#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
243pub struct MavHeader {
244    /// Sender system ID
245    pub system_id: u8,
246    /// Sender component ID
247    pub component_id: u8,
248    /// Packet sequence number
249    pub sequence: u8,
250}
251
252/// [Versions of the MAVLink](https://mavlink.io/en/guide/mavlink_version.html) protocol that we support
253#[derive(Debug, Copy, Clone, PartialEq, Eq)]
254#[cfg_attr(feature = "serde", derive(Serialize))]
255#[cfg_attr(feature = "serde", serde(tag = "type"))]
256#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
257pub enum MavlinkVersion {
258    /// Version v1.0
259    V1,
260    /// Version v2.0
261    V2,
262}
263
264/// Message framing marker for MAVLink 1
265pub const MAV_STX: u8 = 0xFE;
266
267/// Message framing marker for MAVLink 2
268pub const MAV_STX_V2: u8 = 0xFD;
269
270/// Return a default GCS header, seq is replaced by the connector
271/// so it can be ignored. Set `component_id` to your desired component ID.
272impl Default for MavHeader {
273    fn default() -> Self {
274        Self {
275            system_id: 255,
276            component_id: 0,
277            sequence: 0,
278        }
279    }
280}
281
282/// Encapsulation of the MAVLink message and the header,
283/// important to preserve information about the sender system
284/// and component id.
285#[derive(Debug, Clone)]
286#[cfg_attr(feature = "serde", derive(Serialize))]
287#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
288pub struct MavFrame<M: Message> {
289    /// Message header data
290    pub header: MavHeader,
291    /// Parsed [`Message`] payload
292    pub msg: M,
293    /// Messages MAVLink version
294    pub protocol_version: MavlinkVersion,
295}
296
297impl<M: Message> MavFrame<M> {
298    /// Serialize MavFrame into a byte slice, so it can be sent over a socket, for example.
299    /// The resulting buffer will start with the sequence field of the MAVLink frame
300    /// and will not include the initial packet marker, length field, and flags.
301    ///
302    /// # Panics
303    ///
304    /// Will panic if frame does not fit in the provided buffer.
305    pub fn ser(&self, buf: &mut [u8]) -> usize {
306        let mut buf = bytes_mut::BytesMut::new(buf);
307
308        // serialize message
309        let mut payload_buf = [0u8; 255];
310        let payload_len = self.msg.ser(self.protocol_version, &mut payload_buf);
311
312        // Currently expects a buffer with the sequence field at the start.
313        // If this is updated to include the initial packet marker, length field, and flags,
314        // uncomment.
315        //
316        // match self.protocol_version {
317        //     MavlinkVersion::V2 => {
318        //         buf.put_u8(MAV_STX_V2);
319        //         buf.put_u8(payload_len as u8);
320        //         but.put_u8(0); // incompatibility flags
321        //         buf.put_u8(0); // compatibility flags
322        //     }
323        //     MavlinkVersion::V1 => {
324        //         buf.put_u8(MAV_STX);
325        //         buf.put_u8(payload_len as u8);
326        //     }
327        // }
328
329        // serialize header
330        buf.put_u8(self.header.sequence);
331        buf.put_u8(self.header.system_id);
332        buf.put_u8(self.header.component_id);
333
334        // message id
335        match self.protocol_version {
336            MavlinkVersion::V2 => {
337                let bytes: [u8; 4] = self.msg.message_id().to_le_bytes();
338                buf.put_slice(&bytes[..3]);
339            }
340            MavlinkVersion::V1 => {
341                buf.put_u8(self.msg.message_id() as u8); //TODO check
342            }
343        }
344
345        buf.put_slice(&payload_buf[..payload_len]);
346        buf.len()
347    }
348
349    /// Deserialize MavFrame from a slice that has been received from, for example, a socket.
350    /// The input buffer should start with the sequence field of the MAVLink frame. The
351    /// initial packet marker, length field, and flag fields should be excluded.
352    ///
353    /// # Errors
354    ///
355    /// Will return a [`ParserError`] if a message was found but could not be parsed
356    /// or the if the buffer provided does not contain a full message
357    pub fn deser(version: MavlinkVersion, input: &[u8]) -> Result<Self, ParserError> {
358        let mut buf = Bytes::new(input);
359
360        // Currently expects a buffer with the sequence field at the start.
361        // If this is updated to include the initial packet marker, length field, and flags,
362        // uncomment.
363        // <https://mavlink.io/en/guide/serialization.html#mavlink2_packet_format>
364        // match version {
365        //     MavlinkVersion::V2 => buf.get_u32_le(),
366        //     MavlinkVersion::V1 => buf.get_u16_le().into(),
367        // };
368
369        let sequence = buf.get_u8()?;
370        let system_id = buf.get_u8()?;
371        let component_id = buf.get_u8()?;
372        let header = MavHeader {
373            system_id,
374            component_id,
375            sequence,
376        };
377
378        let msg_id = match version {
379            MavlinkVersion::V2 => buf.get_u24_le()?,
380            MavlinkVersion::V1 => buf.get_u8()?.into(),
381        };
382
383        M::parse(version, msg_id, buf.remaining_bytes()).map(|msg| Self {
384            header,
385            msg,
386            protocol_version: version,
387        })
388    }
389
390    /// Return the frame header
391    pub fn header(&self) -> MavHeader {
392        self.header
393    }
394}
395
396/// Calculates the [CRC checksum](https://mavlink.io/en/guide/serialization.html#checksum) of a messages header, payload and the CRC_EXTRA byte.
397pub fn calculate_crc(data: &[u8], extra_crc: u8) -> u16 {
398    let mut crc_calculator = CRCu16::crc16mcrf4cc();
399    crc_calculator.digest(data);
400
401    crc_calculator.digest(&[extra_crc]);
402    crc_calculator.get_crc()
403}
404
405#[derive(Debug, Clone, Copy, PartialEq, Eq)]
406/// MAVLink Version selection when attempting to read
407pub enum ReadVersion {
408    /// Only attempt to read using a single MAVLink version
409    Single(MavlinkVersion),
410    /// Attempt to read messages from both MAVLink versions
411    Any,
412}
413
414impl ReadVersion {
415    #[cfg(feature = "std")]
416    fn from_conn_cfg<C: MavConnection<M>, M: Message>(conn: &C) -> Self {
417        if conn.allow_recv_any_version() {
418            Self::Any
419        } else {
420            conn.protocol_version().into()
421        }
422    }
423    #[cfg(feature = "tokio-1")]
424    fn from_async_conn_cfg<C: AsyncMavConnection<M>, M: Message + Sync + Send>(conn: &C) -> Self {
425        if conn.allow_recv_any_version() {
426            Self::Any
427        } else {
428            conn.protocol_version().into()
429        }
430    }
431}
432
433impl From<MavlinkVersion> for ReadVersion {
434    fn from(value: MavlinkVersion) -> Self {
435        Self::Single(value)
436    }
437}
438
439/// Read and parse a MAVLink message of the specified version from a [`PeekReader`].
440///
441/// # Errors
442///
443/// See [`read_` function error documentation](crate#read-errors)
444pub fn read_versioned_msg<M: Message, R: Read>(
445    r: &mut PeekReader<R>,
446    version: ReadVersion,
447) -> Result<(MavHeader, M), MessageReadError> {
448    match version {
449        ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg(r),
450        ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg(r),
451        ReadVersion::Any => read_any_msg(r),
452    }
453}
454
455/// Read and parse a MAVLink message of the specified version from a [`PeekReader`].
456///
457/// # Errors
458///
459/// See [`read_` function error documentation](crate#read-errors)
460pub fn read_versioned_raw_message<M: Message, R: Read>(
461    r: &mut PeekReader<R>,
462    version: ReadVersion,
463) -> Result<MAVLinkMessageRaw, MessageReadError> {
464    match version {
465        ReadVersion::Single(MavlinkVersion::V2) => {
466            Ok(MAVLinkMessageRaw::V2(read_v2_raw_message::<M, _>(r)?))
467        }
468        ReadVersion::Single(MavlinkVersion::V1) => {
469            Ok(MAVLinkMessageRaw::V1(read_v1_raw_message::<M, _>(r)?))
470        }
471        ReadVersion::Any => read_any_raw_message::<M, _>(r),
472    }
473}
474
475/// Asynchronously read and parse a MAVLink message of the specified version from a [`AsyncPeekReader`].
476///
477/// # Errors
478///
479/// See [`read_` function error documentation](crate#read-errors)
480#[cfg(feature = "tokio-1")]
481pub async fn read_versioned_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
482    r: &mut AsyncPeekReader<R>,
483    version: ReadVersion,
484) -> Result<(MavHeader, M), MessageReadError> {
485    match version {
486        ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_async(r).await,
487        ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg_async(r).await,
488        ReadVersion::Any => read_any_msg_async(r).await,
489    }
490}
491
492/// Asynchronously read and parse a MAVLinkMessageRaw of the specified version from a [`AsyncPeekReader`].
493///
494/// # Errors
495///
496/// See [`read_` function error documentation](crate#read-errors)
497#[cfg(feature = "tokio-1")]
498pub async fn read_versioned_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
499    r: &mut AsyncPeekReader<R>,
500    version: ReadVersion,
501) -> Result<MAVLinkMessageRaw, MessageReadError> {
502    match version {
503        ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
504            read_v2_raw_message_async::<M, _>(r).await?,
505        )),
506        ReadVersion::Single(MavlinkVersion::V1) => Ok(MAVLinkMessageRaw::V1(
507            read_v1_raw_message_async::<M, _>(r).await?,
508        )),
509        ReadVersion::Any => read_any_raw_message_async::<M, _>(r).await,
510    }
511}
512
513/// Read and parse a MAVLinkMessageRaw of the specified version from a [`PeekReader`] with signing support.
514///
515/// When using [`ReadVersion::Single`]`(`[`MavlinkVersion::V1`]`)` signing is ignored.
516/// When using [`ReadVersion::Any`] MAVlink 1 messages are treated as unsigned.
517///
518/// # Errors
519///
520/// See [`read_` function error documentation](crate#read-errors)
521#[cfg(feature = "signing")]
522pub fn read_versioned_raw_message_signed<M: Message, R: Read>(
523    r: &mut PeekReader<R>,
524    version: ReadVersion,
525    signing_data: Option<&SigningData>,
526) -> Result<MAVLinkMessageRaw, MessageReadError> {
527    match version {
528        ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
529            read_v2_raw_message_inner::<M, _>(r, signing_data)?,
530        )),
531        ReadVersion::Single(MavlinkVersion::V1) => {
532            Ok(MAVLinkMessageRaw::V1(read_v1_raw_message::<M, _>(r)?))
533        }
534        ReadVersion::Any => read_any_raw_message_inner::<M, _>(r, signing_data),
535    }
536}
537
538/// Read and parse a MAVLink message of the specified version from a [`PeekReader`] with signing support.
539///
540/// When using [`ReadVersion::Single`]`(`[`MavlinkVersion::V1`]`)` signing is ignored.
541/// When using [`ReadVersion::Any`] MAVlink 1 messages are treated as unsigned.
542///
543/// # Errors
544///
545/// See [`read_` function error documentation](crate#read-errors)
546#[cfg(feature = "signing")]
547pub fn read_versioned_msg_signed<M: Message, R: Read>(
548    r: &mut PeekReader<R>,
549    version: ReadVersion,
550    signing_data: Option<&SigningData>,
551) -> Result<(MavHeader, M), MessageReadError> {
552    match version {
553        ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_inner(r, signing_data),
554        ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg(r),
555        ReadVersion::Any => read_any_msg_inner(r, signing_data),
556    }
557}
558
559/// Asynchronously read and parse a MAVLinkMessageRaw of the specified version from a [`AsyncPeekReader`] with signing support.
560///
561/// When using [`ReadVersion::Single`]`(`[`MavlinkVersion::V1`]`)` signing is ignored.
562/// When using [`ReadVersion::Any`] MAVlink 1 messages are treated as unsigned.
563///
564/// # Errors
565///
566/// See [`read_` function error documentation](crate#read-errors)
567#[cfg(all(feature = "tokio-1", feature = "signing"))]
568pub async fn read_versioned_raw_message_async_signed<
569    M: Message,
570    R: tokio::io::AsyncRead + Unpin,
571>(
572    r: &mut AsyncPeekReader<R>,
573    version: ReadVersion,
574    signing_data: Option<&SigningData>,
575) -> Result<MAVLinkMessageRaw, MessageReadError> {
576    match version {
577        ReadVersion::Single(MavlinkVersion::V2) => Ok(MAVLinkMessageRaw::V2(
578            read_v2_raw_message_async_inner::<M, _>(r, signing_data).await?,
579        )),
580        ReadVersion::Single(MavlinkVersion::V1) => Ok(MAVLinkMessageRaw::V1(
581            read_v1_raw_message_async::<M, _>(r).await?,
582        )),
583        ReadVersion::Any => read_any_raw_message_async_inner::<M, _>(r, signing_data).await,
584    }
585}
586
587/// Asynchronously read and parse a MAVLink message of the specified version from a [`AsyncPeekReader`] with signing support.
588///
589/// When using [`ReadVersion::Single`]`(`[`MavlinkVersion::V1`]`)` signing is ignored.
590/// When using [`ReadVersion::Any`] MAVlink 1 messages are treated as unsigned.
591///
592/// # Errors
593///
594/// See [`read_` function error documentation](crate#read-errors)
595#[cfg(all(feature = "tokio-1", feature = "signing"))]
596pub async fn read_versioned_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
597    r: &mut AsyncPeekReader<R>,
598    version: ReadVersion,
599    signing_data: Option<&SigningData>,
600) -> Result<(MavHeader, M), MessageReadError> {
601    match version {
602        ReadVersion::Single(MavlinkVersion::V2) => read_v2_msg_async_inner(r, signing_data).await,
603        ReadVersion::Single(MavlinkVersion::V1) => read_v1_msg_async(r).await,
604        ReadVersion::Any => read_any_msg_async_inner(r, signing_data).await,
605    }
606}
607
608#[derive(Debug, Copy, Clone, PartialEq, Eq)]
609/// Byte buffer containing the raw representation of a MAVLink 1 message beginning with the STX marker.
610///
611/// Follow protocol definition: <https://mavlink.io/en/guide/serialization.html#v1_packet_format>.
612/// Maximum size is 263 bytes.
613pub struct MAVLinkV1MessageRaw([u8; 1 + Self::HEADER_SIZE + 255 + 2]);
614
615impl Default for MAVLinkV1MessageRaw {
616    fn default() -> Self {
617        Self::new()
618    }
619}
620
621impl MAVLinkV1MessageRaw {
622    const HEADER_SIZE: usize = 5;
623
624    /// Create a new raw MAVLink 1 message filled with zeros.
625    pub const fn new() -> Self {
626        Self([0; 1 + Self::HEADER_SIZE + 255 + 2])
627    }
628
629    /// Create a new raw MAVLink 1 message from a given buffer.
630    ///
631    /// Note: This method does not guarantee that the constructed MAVLink message is valid.
632    pub const fn from_bytes_unparsed(bytes: [u8; 1 + Self::HEADER_SIZE + 255 + 2]) -> Self {
633        Self(bytes)
634    }
635
636    /// Read access to its internal buffer.
637    #[inline]
638    pub fn as_slice(&self) -> &[u8] {
639        &self.0
640    }
641
642    /// Mutable reference to its internal buffer.
643    #[inline]
644    pub fn as_mut_slice(&mut self) -> &mut [u8] {
645        &mut self.0
646    }
647
648    /// Deconstruct the MAVLink message into its owned internal buffer.
649    #[inline]
650    pub fn into_inner(self) -> [u8; 1 + Self::HEADER_SIZE + 255 + 2] {
651        self.0
652    }
653
654    /// Reference to the 5 byte header slice of the message
655    #[inline]
656    pub fn header(&self) -> &[u8] {
657        &self.0[1..=Self::HEADER_SIZE]
658    }
659
660    /// Mutable reference to the 5 byte header slice of the message
661    #[inline]
662    fn mut_header(&mut self) -> &mut [u8] {
663        &mut self.0[1..=Self::HEADER_SIZE]
664    }
665
666    /// Size of the payload of the message
667    #[inline]
668    pub fn payload_length(&self) -> u8 {
669        self.0[1]
670    }
671
672    /// Packet sequence number
673    #[inline]
674    pub fn sequence(&self) -> u8 {
675        self.0[2]
676    }
677
678    /// Message sender System ID
679    #[inline]
680    pub fn system_id(&self) -> u8 {
681        self.0[3]
682    }
683
684    /// Message sender Component ID
685    #[inline]
686    pub fn component_id(&self) -> u8 {
687        self.0[4]
688    }
689
690    /// Message ID
691    #[inline]
692    pub fn message_id(&self) -> u8 {
693        self.0[5]
694    }
695
696    /// Reference to the payload byte slice of the message
697    #[inline]
698    pub fn payload(&self) -> &[u8] {
699        let payload_length: usize = self.payload_length().into();
700        &self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + payload_length)]
701    }
702
703    /// [CRC-16 checksum](https://mavlink.io/en/guide/serialization.html#checksum) field of the message
704    #[inline]
705    pub fn checksum(&self) -> u16 {
706        let payload_length: usize = self.payload_length().into();
707        u16::from_le_bytes([
708            self.0[1 + Self::HEADER_SIZE + payload_length],
709            self.0[1 + Self::HEADER_SIZE + payload_length + 1],
710        ])
711    }
712
713    #[inline]
714    fn mut_payload_and_checksum(&mut self) -> &mut [u8] {
715        let payload_length: usize = self.payload_length().into();
716        &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + payload_length + 2)]
717    }
718
719    /// Checks wether the message’s [CRC-16 checksum](https://mavlink.io/en/guide/serialization.html#checksum) calculation matches its checksum field.
720    #[inline]
721    pub fn has_valid_crc<M: Message>(&self) -> bool {
722        let payload_length: usize = self.payload_length().into();
723        self.checksum()
724            == calculate_crc(
725                &self.0[1..(1 + Self::HEADER_SIZE + payload_length)],
726                M::extra_crc(self.message_id().into()),
727            )
728    }
729
730    /// Raw byte slice of the message
731    pub fn raw_bytes(&self) -> &[u8] {
732        let payload_length = self.payload_length() as usize;
733        &self.0[..(1 + Self::HEADER_SIZE + payload_length + 2)]
734    }
735
736    /// # Panics
737    ///
738    /// If the `msgid` parameter exceeds 255 and is therefore not supported for MAVLink 1
739    fn serialize_stx_and_header_and_crc(
740        &mut self,
741        header: MavHeader,
742        msgid: u32,
743        payload_length: usize,
744        extra_crc: u8,
745    ) {
746        self.0[0] = MAV_STX;
747
748        let header_buf = self.mut_header();
749        header_buf.copy_from_slice(&[
750            payload_length as u8,
751            header.sequence,
752            header.system_id,
753            header.component_id,
754            msgid.try_into().unwrap(),
755        ]);
756
757        let crc = calculate_crc(
758            &self.0[1..(1 + Self::HEADER_SIZE + payload_length)],
759            extra_crc,
760        );
761        self.0[(1 + Self::HEADER_SIZE + payload_length)
762            ..(1 + Self::HEADER_SIZE + payload_length + 2)]
763            .copy_from_slice(&crc.to_le_bytes());
764    }
765
766    /// Serialize a [`Message`] with a given header into this raw message buffer.
767    ///
768    /// # Panics
769    ///
770    /// If the message's id exceeds 255 and is therefore not supported for MAVLink 1
771    pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
772        let payload_buf = &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + 255)];
773        let payload_length = message.ser(MavlinkVersion::V1, payload_buf);
774
775        let message_id = message.message_id();
776        self.serialize_stx_and_header_and_crc(
777            header,
778            message_id,
779            payload_length,
780            M::extra_crc(message_id),
781        );
782    }
783
784    /// # Panics
785    ///
786    /// If the `MessageData`'s `ID` exceeds 255 and is therefore not supported for MAVLink 1
787    pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
788        let payload_buf = &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + 255)];
789        let payload_length = message_data.ser(MavlinkVersion::V1, payload_buf);
790
791        self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC);
792    }
793}
794
795fn try_decode_v1<M: Message, R: Read>(
796    reader: &mut PeekReader<R>,
797) -> Result<Option<MAVLinkV1MessageRaw>, MessageReadError> {
798    let mut message = MAVLinkV1MessageRaw::new();
799    let whole_header_size = MAVLinkV1MessageRaw::HEADER_SIZE + 1;
800
801    message.0[0] = MAV_STX;
802    let header = &reader.peek_exact(whole_header_size)?[1..whole_header_size];
803    message.mut_header().copy_from_slice(header);
804    let packet_length = message.raw_bytes().len();
805    let payload_and_checksum = &reader.peek_exact(packet_length)?[whole_header_size..packet_length];
806    message
807        .mut_payload_and_checksum()
808        .copy_from_slice(payload_and_checksum);
809
810    // retry if CRC failed after previous STX
811    // (an STX byte may appear in the middle of a message)
812    if message.has_valid_crc::<M>() {
813        reader.consume(message.raw_bytes().len());
814        Ok(Some(message))
815    } else {
816        Ok(None)
817    }
818}
819
820#[cfg(feature = "tokio-1")]
821// other then the blocking version the STX is read not peeked, this changed some sizes
822async fn try_decode_v1_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
823    reader: &mut AsyncPeekReader<R>,
824) -> Result<Option<MAVLinkV1MessageRaw>, MessageReadError> {
825    let mut message = MAVLinkV1MessageRaw::new();
826
827    message.0[0] = MAV_STX;
828    let header = &reader.peek_exact(MAVLinkV1MessageRaw::HEADER_SIZE).await?
829        [..MAVLinkV1MessageRaw::HEADER_SIZE];
830    message.mut_header().copy_from_slice(header);
831    let packet_length = message.raw_bytes().len() - 1;
832    let payload_and_checksum =
833        &reader.peek_exact(packet_length).await?[MAVLinkV1MessageRaw::HEADER_SIZE..packet_length];
834    message
835        .mut_payload_and_checksum()
836        .copy_from_slice(payload_and_checksum);
837
838    // retry if CRC failed after previous STX
839    // (an STX byte may appear in the middle of a message)
840    if message.has_valid_crc::<M>() {
841        reader.consume(message.raw_bytes().len() - 1);
842        Ok(Some(message))
843    } else {
844        Ok(None)
845    }
846}
847
848/// Read a raw MAVLink 1 message from a [`PeekReader`].
849///
850/// # Errors
851///
852/// See [`read_` function error documentation](crate#read-errors)
853pub fn read_v1_raw_message<M: Message, R: Read>(
854    reader: &mut PeekReader<R>,
855) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
856    loop {
857        // search for the magic framing value indicating start of mavlink message
858        while reader.peek_exact(1)?[0] != MAV_STX {
859            reader.consume(1);
860        }
861
862        if let Some(msg) = try_decode_v1::<M, _>(reader)? {
863            return Ok(msg);
864        }
865
866        reader.consume(1);
867    }
868}
869
870/// Asynchronously read a raw MAVLink 1 message from a [`AsyncPeekReader`].
871///
872/// # Errors
873///
874/// See [`read_` function error documentation](crate#read-errors)
875#[cfg(feature = "tokio-1")]
876pub async fn read_v1_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
877    reader: &mut AsyncPeekReader<R>,
878) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
879    loop {
880        loop {
881            // search for the magic framing value indicating start of mavlink message
882            if reader.read_u8().await? == MAV_STX {
883                break;
884            }
885        }
886
887        if let Some(message) = try_decode_v1_async::<M, _>(reader).await? {
888            return Ok(message);
889        }
890    }
891}
892
893/// Async read a raw buffer with the mavlink message
894/// V1 maximum size is 263 bytes: `<https://mavlink.io/en/guide/serialization.html>`
895///
896/// # Example
897///
898/// See mavlink/examples/embedded-async-read full example for details.
899#[cfg(feature = "embedded")]
900pub async fn read_v1_raw_message_async<M: Message>(
901    reader: &mut impl embedded_io_async::Read,
902) -> Result<MAVLinkV1MessageRaw, MessageReadError> {
903    loop {
904        // search for the magic framing value indicating start of mavlink message
905        let mut byte = [0u8];
906        loop {
907            reader
908                .read_exact(&mut byte)
909                .await
910                .map_err(|_| MessageReadError::Io)?;
911            if byte[0] == MAV_STX {
912                break;
913            }
914        }
915
916        let mut message = MAVLinkV1MessageRaw::new();
917
918        message.0[0] = MAV_STX;
919        reader
920            .read_exact(message.mut_header())
921            .await
922            .map_err(|_| MessageReadError::Io)?;
923        reader
924            .read_exact(message.mut_payload_and_checksum())
925            .await
926            .map_err(|_| MessageReadError::Io)?;
927
928        // retry if CRC failed after previous STX
929        // (an STX byte may appear in the middle of a message)
930        if message.has_valid_crc::<M>() {
931            return Ok(message);
932        }
933    }
934}
935
936/// Read and parse a MAVLink 1 message from a [`PeekReader`].
937///
938/// # Errors
939///
940/// See [`read_` function error documentation](crate#read-errors)
941pub fn read_v1_msg<M: Message, R: Read>(
942    r: &mut PeekReader<R>,
943) -> Result<(MavHeader, M), MessageReadError> {
944    let message = read_v1_raw_message::<M, _>(r)?;
945
946    Ok((
947        MavHeader {
948            sequence: message.sequence(),
949            system_id: message.system_id(),
950            component_id: message.component_id(),
951        },
952        M::parse(
953            MavlinkVersion::V1,
954            u32::from(message.message_id()),
955            message.payload(),
956        )?,
957    ))
958}
959
960/// Asynchronously read and parse a MAVLink 1 message from a [`AsyncPeekReader`].
961///
962/// # Errors
963///
964/// See [`read_` function error documentation](crate#read-errors)
965#[cfg(feature = "tokio-1")]
966pub async fn read_v1_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
967    r: &mut AsyncPeekReader<R>,
968) -> Result<(MavHeader, M), MessageReadError> {
969    let message = read_v1_raw_message_async::<M, _>(r).await?;
970
971    Ok((
972        MavHeader {
973            sequence: message.sequence(),
974            system_id: message.system_id(),
975            component_id: message.component_id(),
976        },
977        M::parse(
978            MavlinkVersion::V1,
979            u32::from(message.message_id()),
980            message.payload(),
981        )?,
982    ))
983}
984
985/// Asynchronously read and parse a MAVLink 1 message from a [`embedded_io_async::Read`]er.
986///
987/// NOTE: it will be add ~80KB to firmware flash size because all *_DATA::deser methods will be add to firmware.
988/// Use `*_DATA::ser` methods manually to prevent it.
989#[cfg(feature = "embedded")]
990pub async fn read_v1_msg_async<M: Message>(
991    r: &mut impl embedded_io_async::Read,
992) -> Result<(MavHeader, M), MessageReadError> {
993    let message = read_v1_raw_message_async::<M>(r).await?;
994
995    Ok((
996        MavHeader {
997            sequence: message.sequence(),
998            system_id: message.system_id(),
999            component_id: message.component_id(),
1000        },
1001        M::parse(
1002            MavlinkVersion::V1,
1003            u32::from(message.message_id()),
1004            message.payload(),
1005        )?,
1006    ))
1007}
1008
1009const MAVLINK_IFLAG_SIGNED: u8 = 0x01;
1010const MAVLINK_SUPPORTED_IFLAGS: u8 = MAVLINK_IFLAG_SIGNED;
1011
1012#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1013/// Byte buffer containing the raw representation of a MAVLink 2 message beginning with the STX marker.
1014///
1015/// Follow protocol definition: <https://mavlink.io/en/guide/serialization.html#mavlink2_packet_format>.
1016/// Maximum size is [280 bytes](MAX_FRAME_SIZE).
1017pub struct MAVLinkV2MessageRaw([u8; 1 + Self::HEADER_SIZE + 255 + 2 + Self::SIGNATURE_SIZE]);
1018
1019impl Default for MAVLinkV2MessageRaw {
1020    fn default() -> Self {
1021        Self::new()
1022    }
1023}
1024
1025impl MAVLinkV2MessageRaw {
1026    const HEADER_SIZE: usize = 9;
1027    const SIGNATURE_SIZE: usize = 13;
1028
1029    /// Create a new raw MAVLink 2 message filled with zeros.
1030    pub const fn new() -> Self {
1031        Self([0; 1 + Self::HEADER_SIZE + 255 + 2 + Self::SIGNATURE_SIZE])
1032    }
1033
1034    /// Create a new raw MAVLink 1 message from a given buffer.
1035    ///
1036    /// Note: This method does not guarantee that the constructed MAVLink message is valid.
1037    pub const fn from_bytes_unparsed(
1038        bytes: [u8; 1 + Self::HEADER_SIZE + 255 + 2 + Self::SIGNATURE_SIZE],
1039    ) -> Self {
1040        Self(bytes)
1041    }
1042
1043    /// Read access to its internal buffer.
1044    #[inline]
1045    pub fn as_slice(&self) -> &[u8] {
1046        &self.0
1047    }
1048
1049    /// Mutable reference to its internal buffer.
1050    #[inline]
1051    pub fn as_mut_slice(&mut self) -> &mut [u8] {
1052        &mut self.0
1053    }
1054
1055    /// Deconstruct the MAVLink message into its owned internal buffer.
1056    #[inline]
1057    pub fn into_inner(self) -> [u8; 1 + Self::HEADER_SIZE + 255 + 2 + Self::SIGNATURE_SIZE] {
1058        self.0
1059    }
1060
1061    /// Reference to the 9 byte header slice of the message
1062    #[inline]
1063    pub fn header(&self) -> &[u8] {
1064        &self.0[1..=Self::HEADER_SIZE]
1065    }
1066
1067    /// Mutable reference to the header byte slice of the message
1068    #[inline]
1069    fn mut_header(&mut self) -> &mut [u8] {
1070        &mut self.0[1..=Self::HEADER_SIZE]
1071    }
1072
1073    /// Size of the payload of the message
1074    #[inline]
1075    pub fn payload_length(&self) -> u8 {
1076        self.0[1]
1077    }
1078
1079    /// [Incompatiblity flags](https://mavlink.io/en/guide/serialization.html#incompat_flags) of the message
1080    ///
1081    /// Currently the only supported incompatebility flag is `MAVLINK_IFLAG_SIGNED`.
1082    #[inline]
1083    pub fn incompatibility_flags(&self) -> u8 {
1084        self.0[2]
1085    }
1086
1087    /// Mutable reference to the [incompatiblity flags](https://mavlink.io/en/guide/serialization.html#incompat_flags) of the message
1088    ///
1089    /// Currently the only supported incompatebility flag is `MAVLINK_IFLAG_SIGNED`.
1090    #[inline]
1091    pub fn incompatibility_flags_mut(&mut self) -> &mut u8 {
1092        &mut self.0[2]
1093    }
1094
1095    /// [Compatibility Flags](https://mavlink.io/en/guide/serialization.html#compat_flags) of the message
1096    #[inline]
1097    pub fn compatibility_flags(&self) -> u8 {
1098        self.0[3]
1099    }
1100
1101    /// Packet sequence number
1102    #[inline]
1103    pub fn sequence(&self) -> u8 {
1104        self.0[4]
1105    }
1106
1107    /// Message sender System ID
1108    #[inline]
1109    pub fn system_id(&self) -> u8 {
1110        self.0[5]
1111    }
1112
1113    /// Message sender Component ID
1114    #[inline]
1115    pub fn component_id(&self) -> u8 {
1116        self.0[6]
1117    }
1118
1119    /// Message ID
1120    #[inline]
1121    pub fn message_id(&self) -> u32 {
1122        u32::from_le_bytes([self.0[7], self.0[8], self.0[9], 0])
1123    }
1124
1125    /// Reference to the payload byte slice of the message
1126    #[inline]
1127    pub fn payload(&self) -> &[u8] {
1128        let payload_length: usize = self.payload_length().into();
1129        &self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + payload_length)]
1130    }
1131
1132    /// [CRC-16 checksum](https://mavlink.io/en/guide/serialization.html#checksum) field of the message
1133    #[inline]
1134    pub fn checksum(&self) -> u16 {
1135        let payload_length: usize = self.payload_length().into();
1136        u16::from_le_bytes([
1137            self.0[1 + Self::HEADER_SIZE + payload_length],
1138            self.0[1 + Self::HEADER_SIZE + payload_length + 1],
1139        ])
1140    }
1141
1142    /// Reference to the 2 checksum bytes of the message
1143    #[cfg(feature = "signing")]
1144    #[inline]
1145    pub fn checksum_bytes(&self) -> &[u8] {
1146        let checksum_offset = 1 + Self::HEADER_SIZE + self.payload_length() as usize;
1147        &self.0[checksum_offset..(checksum_offset + 2)]
1148    }
1149
1150    /// Signature [Link ID](https://mavlink.io/en/guide/message_signing.html#link_ids)
1151    ///
1152    /// If the message is not signed this 0.
1153    #[cfg(feature = "signing")]
1154    #[inline]
1155    pub fn signature_link_id(&self) -> u8 {
1156        let payload_length: usize = self.payload_length().into();
1157        self.0[1 + Self::HEADER_SIZE + payload_length + 2]
1158    }
1159
1160    /// Mutable reference to the signature [Link ID](https://mavlink.io/en/guide/message_signing.html#link_ids)
1161    #[cfg(feature = "signing")]
1162    #[inline]
1163    pub fn signature_link_id_mut(&mut self) -> &mut u8 {
1164        let payload_length: usize = self.payload_length().into();
1165        &mut self.0[1 + Self::HEADER_SIZE + payload_length + 2]
1166    }
1167
1168    /// Message [signature timestamp](https://mavlink.io/en/guide/message_signing.html#timestamp)
1169    ///
1170    /// The timestamp is a 48 bit number with units of 10 microseconds since 1st January 2015 GMT.
1171    /// The offset since 1st January 1970 (the unix epoch) is 1420070400 seconds.
1172    /// Since all timestamps generated must be at least 1 more than the previous timestamp this timestamp may get ahead of GMT time if there is a burst of packets at a rate of more than 100000 packets per second.
1173    #[cfg(feature = "signing")]
1174    #[inline]
1175    pub fn signature_timestamp(&self) -> u64 {
1176        let mut timestamp_bytes = [0u8; 8];
1177        timestamp_bytes[0..6].copy_from_slice(self.signature_timestamp_bytes());
1178        u64::from_le_bytes(timestamp_bytes)
1179    }
1180
1181    /// 48 bit [signature timestamp](https://mavlink.io/en/guide/message_signing.html#timestamp) byte slice
1182    ///
1183    /// If the message is not signed this contains zeros.
1184    #[cfg(feature = "signing")]
1185    #[inline]
1186    pub fn signature_timestamp_bytes(&self) -> &[u8] {
1187        let payload_length: usize = self.payload_length().into();
1188        let timestamp_start = 1 + Self::HEADER_SIZE + payload_length + 3;
1189        &self.0[timestamp_start..(timestamp_start + 6)]
1190    }
1191
1192    /// Mutable reference to the 48 bit signature timestams byte slice
1193    #[cfg(feature = "signing")]
1194    #[inline]
1195    pub fn signature_timestamp_bytes_mut(&mut self) -> &mut [u8] {
1196        let payload_length: usize = self.payload_length().into();
1197        let timestamp_start = 1 + Self::HEADER_SIZE + payload_length + 3;
1198        &mut self.0[timestamp_start..(timestamp_start + 6)]
1199    }
1200
1201    /// Reference to the 48 bit [message signature](https://mavlink.io/en/guide/message_signing.html#signature) byte slice
1202    ///
1203    /// If the message is not signed this contains zeros.
1204    #[cfg(feature = "signing")]
1205    #[inline]
1206    pub fn signature_value(&self) -> &[u8] {
1207        let payload_length: usize = self.payload_length().into();
1208        let signature_start = 1 + Self::HEADER_SIZE + payload_length + 3 + 6;
1209        &self.0[signature_start..(signature_start + 6)]
1210    }
1211
1212    /// Mutable reference to the 48 bit [message signature](https://mavlink.io/en/guide/message_signing.html#signature) byte slice
1213    #[cfg(feature = "signing")]
1214    #[inline]
1215    pub fn signature_value_mut(&mut self) -> &mut [u8] {
1216        let payload_length: usize = self.payload_length().into();
1217        let signature_start = 1 + Self::HEADER_SIZE + payload_length + 3 + 6;
1218        &mut self.0[signature_start..(signature_start + 6)]
1219    }
1220
1221    fn mut_payload_and_checksum_and_sign(&mut self) -> &mut [u8] {
1222        let payload_length: usize = self.payload_length().into();
1223
1224        // Signature to ensure the link is tamper-proof.
1225        let signature_size = if (self.incompatibility_flags() & MAVLINK_IFLAG_SIGNED) == 0 {
1226            0
1227        } else {
1228            Self::SIGNATURE_SIZE
1229        };
1230
1231        &mut self.0
1232            [(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + payload_length + signature_size + 2)]
1233    }
1234
1235    /// Checks wether the message's [CRC-16 checksum](https://mavlink.io/en/guide/serialization.html#checksum) calculation matches its checksum field.
1236    #[inline]
1237    pub fn has_valid_crc<M: Message>(&self) -> bool {
1238        let payload_length: usize = self.payload_length().into();
1239        self.checksum()
1240            == calculate_crc(
1241                &self.0[1..(1 + Self::HEADER_SIZE + payload_length)],
1242                M::extra_crc(self.message_id()),
1243            )
1244    }
1245
1246    /// Calculates the messages sha256_48 signature.
1247    ///
1248    /// This calculates the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) checksum of messages appended to the 32 byte secret key and copies the first 6 bytes of the result into the target buffer.
1249    #[cfg(feature = "signing")]
1250    pub fn calculate_signature(&self, secret_key: &[u8], target_buffer: &mut [u8; 6]) {
1251        let mut hasher = Sha256::new();
1252        hasher.update(secret_key);
1253        hasher.update([MAV_STX_V2]);
1254        hasher.update(self.header());
1255        hasher.update(self.payload());
1256        hasher.update(self.checksum_bytes());
1257        hasher.update([self.signature_link_id()]);
1258        hasher.update(self.signature_timestamp_bytes());
1259        target_buffer.copy_from_slice(&hasher.finalize()[0..6]);
1260    }
1261
1262    /// Raw byte slice of the message
1263    pub fn raw_bytes(&self) -> &[u8] {
1264        let payload_length = self.payload_length() as usize;
1265
1266        let signature_size = if (self.incompatibility_flags() & MAVLINK_IFLAG_SIGNED) == 0 {
1267            0
1268        } else {
1269            Self::SIGNATURE_SIZE
1270        };
1271
1272        &self.0[..(1 + Self::HEADER_SIZE + payload_length + signature_size + 2)]
1273    }
1274
1275    fn serialize_stx_and_header_and_crc(
1276        &mut self,
1277        header: MavHeader,
1278        msgid: u32,
1279        payload_length: usize,
1280        extra_crc: u8,
1281        incompat_flags: u8,
1282    ) {
1283        self.0[0] = MAV_STX_V2;
1284        let msgid_bytes = msgid.to_le_bytes();
1285
1286        let header_buf = self.mut_header();
1287        header_buf.copy_from_slice(&[
1288            payload_length as u8,
1289            incompat_flags,
1290            0, //compat_flags
1291            header.sequence,
1292            header.system_id,
1293            header.component_id,
1294            msgid_bytes[0],
1295            msgid_bytes[1],
1296            msgid_bytes[2],
1297        ]);
1298
1299        let crc = calculate_crc(
1300            &self.0[1..(1 + Self::HEADER_SIZE + payload_length)],
1301            extra_crc,
1302        );
1303        self.0[(1 + Self::HEADER_SIZE + payload_length)
1304            ..(1 + Self::HEADER_SIZE + payload_length + 2)]
1305            .copy_from_slice(&crc.to_le_bytes());
1306    }
1307
1308    /// Serialize a [Message] with a given header into this raw message buffer.
1309    ///
1310    /// This does not set any compatiblity or incompatiblity flags.
1311    pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
1312        let payload_buf = &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + 255)];
1313        let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
1314
1315        let message_id = message.message_id();
1316        self.serialize_stx_and_header_and_crc(
1317            header,
1318            message_id,
1319            payload_length,
1320            M::extra_crc(message_id),
1321            0,
1322        );
1323    }
1324
1325    /// Serialize a [Message] with a given header into this raw message buffer and sets the `MAVLINK_IFLAG_SIGNED` incompatiblity flag.
1326    ///
1327    /// This does not update the message's signature fields.
1328    /// This does not set any compatiblity flags.
1329    pub fn serialize_message_for_signing<M: Message>(&mut self, header: MavHeader, message: &M) {
1330        let payload_buf = &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + 255)];
1331        let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
1332
1333        let message_id = message.message_id();
1334        self.serialize_stx_and_header_and_crc(
1335            header,
1336            message_id,
1337            payload_length,
1338            M::extra_crc(message_id),
1339            MAVLINK_IFLAG_SIGNED,
1340        );
1341    }
1342
1343    pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
1344        let payload_buf = &mut self.0[(1 + Self::HEADER_SIZE)..(1 + Self::HEADER_SIZE + 255)];
1345        let payload_length = message_data.ser(MavlinkVersion::V2, payload_buf);
1346
1347        self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC, 0);
1348    }
1349}
1350
1351#[allow(unused_variables)]
1352fn try_decode_v2<M: Message, R: Read>(
1353    reader: &mut PeekReader<R>,
1354    signing_data: Option<&SigningData>,
1355) -> Result<Option<MAVLinkV2MessageRaw>, MessageReadError> {
1356    let mut message = MAVLinkV2MessageRaw::new();
1357    let whole_header_size = MAVLinkV2MessageRaw::HEADER_SIZE + 1;
1358
1359    message.0[0] = MAV_STX_V2;
1360    let header = &reader.peek_exact(whole_header_size)?[1..whole_header_size];
1361    message.mut_header().copy_from_slice(header);
1362
1363    if message.incompatibility_flags() & !MAVLINK_SUPPORTED_IFLAGS > 0 {
1364        // if there are incompatibility flags set that we do not know discard the message
1365        reader.consume(1);
1366        return Ok(None);
1367    }
1368
1369    let packet_length = message.raw_bytes().len();
1370    let payload_and_checksum_and_sign =
1371        &reader.peek_exact(packet_length)?[whole_header_size..packet_length];
1372    message
1373        .mut_payload_and_checksum_and_sign()
1374        .copy_from_slice(payload_and_checksum_and_sign);
1375
1376    if message.has_valid_crc::<M>() {
1377        // even if the signature turn out to be invalid the valid crc shows that the received data presents a valid message as opposed to random bytes
1378        reader.consume(message.raw_bytes().len());
1379    } else {
1380        reader.consume(1);
1381        return Ok(None);
1382    }
1383
1384    #[cfg(feature = "signing")]
1385    if let Some(signing_data) = signing_data {
1386        if !signing_data.verify_signature(&message) {
1387            return Ok(None);
1388        }
1389    }
1390
1391    Ok(Some(message))
1392}
1393
1394#[cfg(feature = "tokio-1")]
1395#[allow(unused_variables)]
1396// other then the blocking version the STX is read not peeked, this changed some sizes
1397async fn try_decode_v2_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1398    reader: &mut AsyncPeekReader<R>,
1399    signing_data: Option<&SigningData>,
1400) -> Result<Option<MAVLinkV2MessageRaw>, MessageReadError> {
1401    let mut message = MAVLinkV2MessageRaw::new();
1402
1403    message.0[0] = MAV_STX_V2;
1404    let header = &reader.peek_exact(MAVLinkV2MessageRaw::HEADER_SIZE).await?
1405        [..MAVLinkV2MessageRaw::HEADER_SIZE];
1406    message.mut_header().copy_from_slice(header);
1407
1408    if message.incompatibility_flags() & !MAVLINK_SUPPORTED_IFLAGS > 0 {
1409        // if there are incompatibility flags set that we do not know discard the message
1410        return Ok(None);
1411    }
1412
1413    let packet_length = message.raw_bytes().len() - 1;
1414    let payload_and_checksum_and_sign =
1415        &reader.peek_exact(packet_length).await?[MAVLinkV2MessageRaw::HEADER_SIZE..packet_length];
1416    message
1417        .mut_payload_and_checksum_and_sign()
1418        .copy_from_slice(payload_and_checksum_and_sign);
1419
1420    if message.has_valid_crc::<M>() {
1421        // even if the signature turn out to be invalid the valid crc shows that the received data presents a valid message as opposed to random bytes
1422        reader.consume(message.raw_bytes().len() - 1);
1423    } else {
1424        return Ok(None);
1425    }
1426
1427    #[cfg(feature = "signing")]
1428    if let Some(signing_data) = signing_data {
1429        if !signing_data.verify_signature(&message) {
1430            return Ok(None);
1431        }
1432    }
1433
1434    Ok(Some(message))
1435}
1436
1437/// Read a raw MAVLink 2 message from a [`PeekReader`].
1438///
1439/// # Errors
1440///
1441/// See [`read_` function error documentation](crate#read-errors)
1442#[inline]
1443pub fn read_v2_raw_message<M: Message, R: Read>(
1444    reader: &mut PeekReader<R>,
1445) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1446    read_v2_raw_message_inner::<M, R>(reader, None)
1447}
1448
1449/// Read a raw MAVLink 2 message with signing support from a [`PeekReader`].
1450///
1451/// # Errors
1452///
1453/// See [`read_` function error documentation](crate#read-errors)
1454#[cfg(feature = "signing")]
1455#[inline]
1456pub fn read_v2_raw_message_signed<M: Message, R: Read>(
1457    reader: &mut PeekReader<R>,
1458    signing_data: Option<&SigningData>,
1459) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1460    read_v2_raw_message_inner::<M, R>(reader, signing_data)
1461}
1462
1463#[allow(unused_variables)]
1464fn read_v2_raw_message_inner<M: Message, R: Read>(
1465    reader: &mut PeekReader<R>,
1466    signing_data: Option<&SigningData>,
1467) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1468    loop {
1469        // search for the magic framing value indicating start of mavlink message
1470        while reader.peek_exact(1)?[0] != MAV_STX_V2 {
1471            reader.consume(1);
1472        }
1473
1474        if let Some(message) = try_decode_v2::<M, _>(reader, signing_data)? {
1475            return Ok(message);
1476        }
1477    }
1478}
1479
1480/// Asynchronously read a raw MAVLink 2 message from a [`AsyncPeekReader`].
1481///
1482/// # Errors
1483///
1484/// See [`read_` function error documentation](crate#read-errors)
1485#[cfg(feature = "tokio-1")]
1486pub async fn read_v2_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1487    reader: &mut AsyncPeekReader<R>,
1488) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1489    read_v2_raw_message_async_inner::<M, R>(reader, None).await
1490}
1491
1492#[cfg(feature = "tokio-1")]
1493#[allow(unused_variables)]
1494async fn read_v2_raw_message_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1495    reader: &mut AsyncPeekReader<R>,
1496    signing_data: Option<&SigningData>,
1497) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1498    loop {
1499        loop {
1500            // search for the magic framing value indicating start of mavlink message
1501            if reader.read_u8().await? == MAV_STX_V2 {
1502                break;
1503            }
1504        }
1505
1506        if let Some(message) = try_decode_v2_async::<M, _>(reader, signing_data).await? {
1507            return Ok(message);
1508        }
1509    }
1510}
1511
1512/// Asynchronously read a raw MAVLink 2 message with signing support from a [`AsyncPeekReader`]
1513///
1514/// # Errors
1515///
1516/// See [`read_` function error documentation](crate#read-errors)
1517#[cfg(all(feature = "tokio-1", feature = "signing"))]
1518pub async fn read_v2_raw_message_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1519    reader: &mut AsyncPeekReader<R>,
1520    signing_data: Option<&SigningData>,
1521) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1522    read_v2_raw_message_async_inner::<M, R>(reader, signing_data).await
1523}
1524
1525/// Asynchronously read a raw MAVLink 2 message with signing support from a [`embedded_io_async::Read`]er.
1526///
1527/// # Example
1528///
1529/// See mavlink/examples/embedded-async-read full example for details.
1530#[cfg(feature = "embedded")]
1531pub async fn read_v2_raw_message_async<M: Message>(
1532    reader: &mut impl embedded_io_async::Read,
1533) -> Result<MAVLinkV2MessageRaw, MessageReadError> {
1534    loop {
1535        // search for the magic framing value indicating start of mavlink message
1536        let mut byte = [0u8];
1537        loop {
1538            reader
1539                .read_exact(&mut byte)
1540                .await
1541                .map_err(|_| MessageReadError::Io)?;
1542            if byte[0] == MAV_STX_V2 {
1543                break;
1544            }
1545        }
1546
1547        let mut message = MAVLinkV2MessageRaw::new();
1548
1549        message.0[0] = MAV_STX_V2;
1550        reader
1551            .read_exact(message.mut_header())
1552            .await
1553            .map_err(|_| MessageReadError::Io)?;
1554
1555        if message.incompatibility_flags() & !MAVLINK_SUPPORTED_IFLAGS > 0 {
1556            // if there are incompatibility flags set that we do not know discard the message
1557            continue;
1558        }
1559
1560        reader
1561            .read_exact(message.mut_payload_and_checksum_and_sign())
1562            .await
1563            .map_err(|_| MessageReadError::Io)?;
1564
1565        // retry if CRC failed after previous STX
1566        // (an STX byte may appear in the middle of a message)
1567        if message.has_valid_crc::<M>() {
1568            return Ok(message);
1569        }
1570    }
1571}
1572
1573/// Read and parse a MAVLink 2 message from a [`PeekReader`].
1574///
1575/// # Errors
1576///
1577/// See [`read_` function error documentation](crate#read-errors)
1578#[inline]
1579pub fn read_v2_msg<M: Message, R: Read>(
1580    read: &mut PeekReader<R>,
1581) -> Result<(MavHeader, M), MessageReadError> {
1582    read_v2_msg_inner(read, None)
1583}
1584
1585/// Read and parse a MAVLink 2 message from a [`PeekReader`].
1586///
1587/// # Errors
1588///
1589/// See [`read_` function error documentation](crate#read-errors)
1590#[cfg(feature = "signing")]
1591#[inline]
1592pub fn read_v2_msg_signed<M: Message, R: Read>(
1593    read: &mut PeekReader<R>,
1594    signing_data: Option<&SigningData>,
1595) -> Result<(MavHeader, M), MessageReadError> {
1596    read_v2_msg_inner(read, signing_data)
1597}
1598
1599fn read_v2_msg_inner<M: Message, R: Read>(
1600    read: &mut PeekReader<R>,
1601    signing_data: Option<&SigningData>,
1602) -> Result<(MavHeader, M), MessageReadError> {
1603    let message = read_v2_raw_message_inner::<M, _>(read, signing_data)?;
1604
1605    Ok((
1606        MavHeader {
1607            sequence: message.sequence(),
1608            system_id: message.system_id(),
1609            component_id: message.component_id(),
1610        },
1611        M::parse(MavlinkVersion::V2, message.message_id(), message.payload())?,
1612    ))
1613}
1614
1615/// Asynchronously read and parse a MAVLink 2 message from a [`AsyncPeekReader`].
1616///  
1617/// # Errors
1618///
1619/// See [`read_` function error documentation](crate#read-errors)
1620#[cfg(feature = "tokio-1")]
1621pub async fn read_v2_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1622    read: &mut AsyncPeekReader<R>,
1623) -> Result<(MavHeader, M), MessageReadError> {
1624    read_v2_msg_async_inner(read, None).await
1625}
1626
1627/// Asynchronously read and parse a MAVLink 2 message with signing support from a [`AsyncPeekReader`].
1628///
1629/// # Errors
1630///
1631/// See [`read_` function error documentation](crate#read-errors)
1632#[cfg(all(feature = "tokio-1", feature = "signing"))]
1633pub async fn read_v2_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1634    read: &mut AsyncPeekReader<R>,
1635    signing_data: Option<&SigningData>,
1636) -> Result<(MavHeader, M), MessageReadError> {
1637    read_v2_msg_async_inner(read, signing_data).await
1638}
1639
1640#[cfg(feature = "tokio-1")]
1641async fn read_v2_msg_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1642    read: &mut AsyncPeekReader<R>,
1643    signing_data: Option<&SigningData>,
1644) -> Result<(MavHeader, M), MessageReadError> {
1645    let message = read_v2_raw_message_async_inner::<M, _>(read, signing_data).await?;
1646
1647    Ok((
1648        MavHeader {
1649            sequence: message.sequence(),
1650            system_id: message.system_id(),
1651            component_id: message.component_id(),
1652        },
1653        M::parse(MavlinkVersion::V2, message.message_id(), message.payload())?,
1654    ))
1655}
1656
1657/// Asynchronously and parse read a MAVLink 2 message from a [`embedded_io_async::Read`]er.
1658///
1659/// NOTE: it will be add ~80KB to firmware flash size because all *_DATA::deser methods will be add to firmware.
1660/// Use `*_DATA::deser` methods manually to prevent it.
1661#[cfg(feature = "embedded")]
1662pub async fn read_v2_msg_async<M: Message, R: embedded_io_async::Read>(
1663    r: &mut R,
1664) -> Result<(MavHeader, M), MessageReadError> {
1665    let message = read_v2_raw_message_async::<M>(r).await?;
1666
1667    Ok((
1668        MavHeader {
1669            sequence: message.sequence(),
1670            system_id: message.system_id(),
1671            component_id: message.component_id(),
1672        },
1673        M::parse(
1674            MavlinkVersion::V2,
1675            u32::from(message.message_id()),
1676            message.payload(),
1677        )?,
1678    ))
1679}
1680
1681/// Raw byte representation of a MAVLink message of either version
1682pub enum MAVLinkMessageRaw {
1683    V1(MAVLinkV1MessageRaw),
1684    V2(MAVLinkV2MessageRaw),
1685}
1686
1687impl MAVLinkMessageRaw {
1688    pub fn payload(&self) -> &[u8] {
1689        match self {
1690            Self::V1(msg) => msg.payload(),
1691            Self::V2(msg) => msg.payload(),
1692        }
1693    }
1694    pub fn sequence(&self) -> u8 {
1695        match self {
1696            Self::V1(msg) => msg.sequence(),
1697            Self::V2(msg) => msg.sequence(),
1698        }
1699    }
1700    pub fn system_id(&self) -> u8 {
1701        match self {
1702            Self::V1(msg) => msg.system_id(),
1703            Self::V2(msg) => msg.system_id(),
1704        }
1705    }
1706    pub fn component_id(&self) -> u8 {
1707        match self {
1708            Self::V1(msg) => msg.component_id(),
1709            Self::V2(msg) => msg.component_id(),
1710        }
1711    }
1712    pub fn message_id(&self) -> u32 {
1713        match self {
1714            Self::V1(msg) => u32::from(msg.message_id()),
1715            Self::V2(msg) => msg.message_id(),
1716        }
1717    }
1718    pub fn version(&self) -> MavlinkVersion {
1719        match self {
1720            Self::V1(_) => MavlinkVersion::V1,
1721            Self::V2(_) => MavlinkVersion::V2,
1722        }
1723    }
1724}
1725
1726/// Read a raw MAVLink 1 or 2 message from a [`PeekReader`].
1727///
1728/// # Errors
1729///
1730/// See [`read_` function error documentation](crate#read-errors)
1731#[inline]
1732pub fn read_any_raw_message<M: Message, R: Read>(
1733    reader: &mut PeekReader<R>,
1734) -> Result<MAVLinkMessageRaw, MessageReadError> {
1735    read_any_raw_message_inner::<M, R>(reader, None)
1736}
1737
1738/// Read a raw MAVLink 1 or 2 message from a [`PeekReader`] with signing support.
1739///
1740/// # Errors
1741///
1742/// See [`read_` function error documentation](crate#read-errors)
1743#[cfg(feature = "signing")]
1744#[inline]
1745pub fn read_any_raw_message_signed<M: Message, R: Read>(
1746    reader: &mut PeekReader<R>,
1747    signing_data: Option<&SigningData>,
1748) -> Result<MAVLinkMessageRaw, MessageReadError> {
1749    read_any_raw_message_inner::<M, R>(reader, signing_data)
1750}
1751
1752#[allow(unused_variables)]
1753fn read_any_raw_message_inner<M: Message, R: Read>(
1754    reader: &mut PeekReader<R>,
1755    signing_data: Option<&SigningData>,
1756) -> Result<MAVLinkMessageRaw, MessageReadError> {
1757    loop {
1758        // search for the magic framing value indicating start of MAVLink message
1759        let version = loop {
1760            let byte = reader.peek_exact(1)?[0];
1761            if byte == MAV_STX {
1762                break MavlinkVersion::V1;
1763            }
1764            if byte == MAV_STX_V2 {
1765                break MavlinkVersion::V2;
1766            }
1767            reader.consume(1);
1768        };
1769        match version {
1770            MavlinkVersion::V1 => {
1771                if let Some(message) = try_decode_v1::<M, _>(reader)? {
1772                    // With signing enabled and unsigned messages not allowed do not further process V1
1773                    #[cfg(feature = "signing")]
1774                    if let Some(signing) = signing_data {
1775                        if signing.config.allow_unsigned {
1776                            return Ok(MAVLinkMessageRaw::V1(message));
1777                        }
1778                    } else {
1779                        return Ok(MAVLinkMessageRaw::V1(message));
1780                    }
1781                    #[cfg(not(feature = "signing"))]
1782                    return Ok(MAVLinkMessageRaw::V1(message));
1783                }
1784
1785                reader.consume(1);
1786            }
1787            MavlinkVersion::V2 => {
1788                if let Some(message) = try_decode_v2::<M, _>(reader, signing_data)? {
1789                    return Ok(MAVLinkMessageRaw::V2(message));
1790                }
1791            }
1792        }
1793    }
1794}
1795
1796/// Asynchronously read a raw MAVLink 1 or 2 message from a [`AsyncPeekReader`].
1797///
1798/// # Errors
1799///
1800/// See [`read_` function error documentation](crate#read-errors)
1801#[cfg(feature = "tokio-1")]
1802pub async fn read_any_raw_message_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1803    reader: &mut AsyncPeekReader<R>,
1804) -> Result<MAVLinkMessageRaw, MessageReadError> {
1805    read_any_raw_message_async_inner::<M, R>(reader, None).await
1806}
1807
1808/// Asynchronously read a raw MAVLink 1 or 2 message from a [`AsyncPeekReader`] with signing support.
1809///
1810/// This will attempt to read until encounters a valid message or an error.
1811///
1812/// # Errors
1813///
1814/// See [`read_` function error documentation](crate#read-errors)
1815#[cfg(all(feature = "tokio-1", feature = "signing"))]
1816pub async fn read_any_raw_message_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1817    reader: &mut AsyncPeekReader<R>,
1818    signing_data: Option<&SigningData>,
1819) -> Result<MAVLinkMessageRaw, MessageReadError> {
1820    read_any_raw_message_async_inner::<M, R>(reader, signing_data).await
1821}
1822
1823#[cfg(feature = "tokio-1")]
1824#[allow(unused_variables)]
1825async fn read_any_raw_message_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1826    reader: &mut AsyncPeekReader<R>,
1827    signing_data: Option<&SigningData>,
1828) -> Result<MAVLinkMessageRaw, MessageReadError> {
1829    loop {
1830        // search for the magic framing value indicating start of MAVLink 1 or 2 message
1831        let version = loop {
1832            let read = reader.read_u8().await?;
1833            if read == MAV_STX {
1834                break MavlinkVersion::V1;
1835            }
1836            if read == MAV_STX_V2 {
1837                break MavlinkVersion::V2;
1838            }
1839        };
1840
1841        match version {
1842            MavlinkVersion::V1 => {
1843                if let Some(message) = try_decode_v1_async::<M, _>(reader).await? {
1844                    // With signing enabled and unsigned messages not allowed do not further process them
1845                    #[cfg(feature = "signing")]
1846                    if let Some(signing) = signing_data {
1847                        if signing.config.allow_unsigned {
1848                            return Ok(MAVLinkMessageRaw::V1(message));
1849                        }
1850                    } else {
1851                        return Ok(MAVLinkMessageRaw::V1(message));
1852                    }
1853                    #[cfg(not(feature = "signing"))]
1854                    return Ok(MAVLinkMessageRaw::V1(message));
1855                }
1856            }
1857            MavlinkVersion::V2 => {
1858                if let Some(message) = try_decode_v2_async::<M, _>(reader, signing_data).await? {
1859                    return Ok(MAVLinkMessageRaw::V2(message));
1860                }
1861            }
1862        }
1863    }
1864}
1865
1866/// Read and parse a MAVLink 1 or 2 message from a [`PeekReader`].
1867///
1868/// # Errors
1869///
1870/// See [`read_` function error documentation](crate#read-errors)
1871#[inline]
1872pub fn read_any_msg<M: Message, R: Read>(
1873    read: &mut PeekReader<R>,
1874) -> Result<(MavHeader, M), MessageReadError> {
1875    read_any_msg_inner(read, None)
1876}
1877
1878/// Read and parse a MAVLink 1 or 2 message from a [`PeekReader`] with signing support.
1879///
1880/// MAVLink 1 messages a treated as unsigned.
1881///
1882/// # Errors
1883///
1884/// See [`read_` function error documentation](crate#read-errors)
1885#[cfg(feature = "signing")]
1886#[inline]
1887pub fn read_any_msg_signed<M: Message, R: Read>(
1888    read: &mut PeekReader<R>,
1889    signing_data: Option<&SigningData>,
1890) -> Result<(MavHeader, M), MessageReadError> {
1891    read_any_msg_inner(read, signing_data)
1892}
1893
1894fn read_any_msg_inner<M: Message, R: Read>(
1895    read: &mut PeekReader<R>,
1896    signing_data: Option<&SigningData>,
1897) -> Result<(MavHeader, M), MessageReadError> {
1898    let message = read_any_raw_message_inner::<M, _>(read, signing_data)?;
1899    Ok((
1900        MavHeader {
1901            sequence: message.sequence(),
1902            system_id: message.system_id(),
1903            component_id: message.component_id(),
1904        },
1905        M::parse(message.version(), message.message_id(), message.payload())?,
1906    ))
1907}
1908
1909/// Asynchronously read and parse a MAVLink 1 or 2 message from a [`AsyncPeekReader`].
1910///
1911/// # Errors
1912///
1913/// See [`read_` function error documentation](crate#read-errors)
1914#[cfg(feature = "tokio-1")]
1915pub async fn read_any_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
1916    read: &mut AsyncPeekReader<R>,
1917) -> Result<(MavHeader, M), MessageReadError> {
1918    read_any_msg_async_inner(read, None).await
1919}
1920
1921/// Asynchronously read and parse a MAVLink 1 or 2 message from a [`AsyncPeekReader`] with signing support.
1922///
1923/// MAVLink 1 messages a treated as unsigned.
1924///
1925/// # Errors
1926///
1927/// See [`read_` function error documentation](crate#read-errors)
1928#[cfg(all(feature = "tokio-1", feature = "signing"))]
1929#[inline]
1930pub async fn read_any_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
1931    read: &mut AsyncPeekReader<R>,
1932    signing_data: Option<&SigningData>,
1933) -> Result<(MavHeader, M), MessageReadError> {
1934    read_any_msg_async_inner(read, signing_data).await
1935}
1936
1937#[cfg(feature = "tokio-1")]
1938async fn read_any_msg_async_inner<M: Message, R: tokio::io::AsyncRead + Unpin>(
1939    read: &mut AsyncPeekReader<R>,
1940    signing_data: Option<&SigningData>,
1941) -> Result<(MavHeader, M), MessageReadError> {
1942    let message = read_any_raw_message_async_inner::<M, _>(read, signing_data).await?;
1943
1944    Ok((
1945        MavHeader {
1946            sequence: message.sequence(),
1947            system_id: message.system_id(),
1948            component_id: message.component_id(),
1949        },
1950        M::parse(message.version(), message.message_id(), message.payload())?,
1951    ))
1952}
1953
1954/// Write a MAVLink message using the given mavlink version to a [`Write`]r.
1955///
1956/// # Errors
1957///
1958/// See [`write_` function error documentation](crate#write-errors).
1959pub fn write_versioned_msg<M: Message, W: Write>(
1960    w: &mut W,
1961    version: MavlinkVersion,
1962    header: MavHeader,
1963    data: &M,
1964) -> Result<usize, MessageWriteError> {
1965    match version {
1966        MavlinkVersion::V2 => write_v2_msg(w, header, data),
1967        MavlinkVersion::V1 => write_v1_msg(w, header, data),
1968    }
1969}
1970
1971/// Write a MAVLink message using the given mavlink version to a [`Write`]r with signing support.
1972///
1973/// When using [`MavlinkVersion::V1`] signing is ignored.
1974///
1975/// # Errors
1976///
1977/// See [`write_` function error documentation](crate#write-errors).
1978#[cfg(feature = "signing")]
1979pub fn write_versioned_msg_signed<M: Message, W: Write>(
1980    w: &mut W,
1981    version: MavlinkVersion,
1982    header: MavHeader,
1983    data: &M,
1984    signing_data: Option<&SigningData>,
1985) -> Result<usize, MessageWriteError> {
1986    match version {
1987        MavlinkVersion::V2 => write_v2_msg_signed(w, header, data, signing_data),
1988        MavlinkVersion::V1 => write_v1_msg(w, header, data),
1989    }
1990}
1991
1992/// Asynchronously write a MAVLink message using the given MAVLink version to a [`AsyncWrite`]r.
1993///
1994/// # Errors
1995///
1996/// See [`write_` function error documentation](crate#write-errors).
1997#[cfg(feature = "tokio-1")]
1998pub async fn write_versioned_msg_async<M: Message, W: AsyncWrite + Unpin>(
1999    w: &mut W,
2000    version: MavlinkVersion,
2001    header: MavHeader,
2002    data: &M,
2003) -> Result<usize, MessageWriteError> {
2004    match version {
2005        MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
2006        MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2007    }
2008}
2009
2010/// Asynchronously write a MAVLink message using the given MAVLink version to a [`AsyncWrite`]r with signing support.
2011///
2012/// When using [`MavlinkVersion::V1`] signing is ignored.
2013///
2014/// # Errors
2015///
2016/// See [`write_` function error documentation](crate#write-errors).
2017#[cfg(all(feature = "tokio-1", feature = "signing"))]
2018pub async fn write_versioned_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
2019    w: &mut W,
2020    version: MavlinkVersion,
2021    header: MavHeader,
2022    data: &M,
2023    signing_data: Option<&SigningData>,
2024) -> Result<usize, MessageWriteError> {
2025    match version {
2026        MavlinkVersion::V2 => write_v2_msg_async_signed(w, header, data, signing_data).await,
2027        MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2028    }
2029}
2030
2031/// Asynchronously write a MAVLink message using the given MAVLink version to a [`embedded_io_async::Write`]r.
2032///
2033/// NOTE: it will be add ~70KB to firmware flash size because all *_DATA::ser methods will be add to firmware.
2034/// Use `*_DATA::ser` methods manually to prevent it.
2035#[cfg(feature = "embedded")]
2036pub async fn write_versioned_msg_async<M: Message>(
2037    w: &mut impl embedded_io_async::Write,
2038    version: MavlinkVersion,
2039    header: MavHeader,
2040    data: &M,
2041) -> Result<usize, MessageWriteError> {
2042    match version {
2043        MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
2044        MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
2045    }
2046}
2047
2048/// Write a MAVLink 2 message to a [`Write`]r.
2049///
2050/// # Errors
2051///
2052/// See [`write_` function error documentation](crate#write-errors).
2053pub fn write_v2_msg<M: Message, W: Write>(
2054    w: &mut W,
2055    header: MavHeader,
2056    data: &M,
2057) -> Result<usize, MessageWriteError> {
2058    let mut message_raw = MAVLinkV2MessageRaw::new();
2059    message_raw.serialize_message(header, data);
2060
2061    let payload_length: usize = message_raw.payload_length().into();
2062    let len = 1 + MAVLinkV2MessageRaw::HEADER_SIZE + payload_length + 2;
2063
2064    w.write_all(&message_raw.0[..len])?;
2065
2066    Ok(len)
2067}
2068
2069/// Write a MAVLink 2 message to a [`Write`]r with signing support.
2070///
2071/// # Errors
2072///
2073/// See [`write_` function error documentation](crate#write-errors).
2074#[cfg(feature = "signing")]
2075pub fn write_v2_msg_signed<M: Message, W: Write>(
2076    w: &mut W,
2077    header: MavHeader,
2078    data: &M,
2079    signing_data: Option<&SigningData>,
2080) -> Result<usize, MessageWriteError> {
2081    let mut message_raw = MAVLinkV2MessageRaw::new();
2082
2083    let signature_len = if let Some(signing_data) = signing_data {
2084        if signing_data.config.sign_outgoing {
2085            message_raw.serialize_message_for_signing(header, data);
2086            signing_data.sign_message(&mut message_raw);
2087            MAVLinkV2MessageRaw::SIGNATURE_SIZE
2088        } else {
2089            message_raw.serialize_message(header, data);
2090            0
2091        }
2092    } else {
2093        message_raw.serialize_message(header, data);
2094        0
2095    };
2096
2097    let payload_length: usize = message_raw.payload_length().into();
2098    let len = 1 + MAVLinkV2MessageRaw::HEADER_SIZE + payload_length + 2 + signature_len;
2099
2100    w.write_all(&message_raw.0[..len])?;
2101
2102    Ok(len)
2103}
2104
2105/// Asynchronously write a MAVLink 2 message to a [`AsyncWrite`]r.
2106///
2107/// # Errors
2108///
2109/// See [`write_` function error documentation](crate#write-errors).
2110#[cfg(feature = "tokio-1")]
2111pub async fn write_v2_msg_async<M: Message, W: AsyncWrite + Unpin>(
2112    w: &mut W,
2113    header: MavHeader,
2114    data: &M,
2115) -> Result<usize, MessageWriteError> {
2116    let mut message_raw = MAVLinkV2MessageRaw::new();
2117    message_raw.serialize_message(header, data);
2118
2119    let payload_length: usize = message_raw.payload_length().into();
2120    let len = 1 + MAVLinkV2MessageRaw::HEADER_SIZE + payload_length + 2;
2121
2122    w.write_all(&message_raw.0[..len]).await?;
2123
2124    Ok(len)
2125}
2126
2127/// Write a MAVLink 2 message to a [`AsyncWrite`]r with signing support.
2128///
2129/// # Errors
2130///
2131/// See [`write_` function error documentation](crate#write-errors).
2132#[cfg(feature = "signing")]
2133#[cfg(feature = "tokio-1")]
2134pub async fn write_v2_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
2135    w: &mut W,
2136    header: MavHeader,
2137    data: &M,
2138    signing_data: Option<&SigningData>,
2139) -> Result<usize, MessageWriteError> {
2140    let mut message_raw = MAVLinkV2MessageRaw::new();
2141
2142    let signature_len = if let Some(signing_data) = signing_data {
2143        if signing_data.config.sign_outgoing {
2144            message_raw.serialize_message_for_signing(header, data);
2145            signing_data.sign_message(&mut message_raw);
2146            MAVLinkV2MessageRaw::SIGNATURE_SIZE
2147        } else {
2148            message_raw.serialize_message(header, data);
2149            0
2150        }
2151    } else {
2152        message_raw.serialize_message(header, data);
2153        0
2154    };
2155
2156    let payload_length: usize = message_raw.payload_length().into();
2157    let len = 1 + MAVLinkV2MessageRaw::HEADER_SIZE + payload_length + 2 + signature_len;
2158
2159    w.write_all(&message_raw.0[..len]).await?;
2160
2161    Ok(len)
2162}
2163
2164/// Asynchronously write a MAVLink 2 message to a [`embedded_io_async::Write`]r.
2165///
2166/// NOTE: it will be add ~70KB to firmware flash size because all *_DATA::ser methods will be add to firmware.
2167/// Use `*_DATA::ser` methods manually to prevent it.
2168///
2169/// # Errors
2170///
2171/// Returns the first error that occurs when writing to the [`embedded_io_async::Write`]r.
2172#[cfg(feature = "embedded")]
2173pub async fn write_v2_msg_async<M: Message>(
2174    w: &mut impl embedded_io_async::Write,
2175    header: MavHeader,
2176    data: &M,
2177) -> Result<usize, MessageWriteError> {
2178    let mut message_raw = MAVLinkV2MessageRaw::new();
2179    message_raw.serialize_message(header, data);
2180
2181    let payload_length: usize = message_raw.payload_length().into();
2182    let len = 1 + MAVLinkV2MessageRaw::HEADER_SIZE + payload_length + 2;
2183
2184    w.write_all(&message_raw.0[..len])
2185        .await
2186        .map_err(|_| MessageWriteError::Io)?;
2187
2188    Ok(len)
2189}
2190
2191/// Write a MAVLink 1 message to a [`Write`]r.
2192///
2193/// # Errors
2194///
2195/// See [`write_` function error documentation](crate#write-errors).
2196pub fn write_v1_msg<M: Message, W: Write>(
2197    w: &mut W,
2198    header: MavHeader,
2199    data: &M,
2200) -> Result<usize, MessageWriteError> {
2201    if data.message_id() > u8::MAX.into() {
2202        return Err(MessageWriteError::MAVLink2Only);
2203    }
2204    let mut message_raw = MAVLinkV1MessageRaw::new();
2205    message_raw.serialize_message(header, data);
2206
2207    let payload_length: usize = message_raw.payload_length().into();
2208    let len = 1 + MAVLinkV1MessageRaw::HEADER_SIZE + payload_length + 2;
2209
2210    w.write_all(&message_raw.0[..len])?;
2211
2212    Ok(len)
2213}
2214
2215/// Asynchronously write a MAVLink 1 message to a [`AsyncWrite`]r.
2216///
2217/// # Errors
2218///
2219/// Returns the first error that occurs when writing to the [`AsyncWrite`]r.
2220#[cfg(feature = "tokio-1")]
2221pub async fn write_v1_msg_async<M: Message, W: AsyncWrite + Unpin>(
2222    w: &mut W,
2223    header: MavHeader,
2224    data: &M,
2225) -> Result<usize, MessageWriteError> {
2226    if data.message_id() > u8::MAX.into() {
2227        return Err(MessageWriteError::MAVLink2Only);
2228    }
2229    let mut message_raw = MAVLinkV1MessageRaw::new();
2230    message_raw.serialize_message(header, data);
2231
2232    let payload_length: usize = message_raw.payload_length().into();
2233    let len = 1 + MAVLinkV1MessageRaw::HEADER_SIZE + payload_length + 2;
2234
2235    w.write_all(&message_raw.0[..len]).await?;
2236
2237    Ok(len)
2238}
2239
2240/// Write a MAVLink 1 message to a [`embedded_io_async::Write`]r.
2241///
2242/// NOTE: it will be add ~70KB to firmware flash size because all *_DATA::ser methods will be add to firmware.
2243/// Use `*_DATA::ser` methods manually to prevent it.
2244#[cfg(feature = "embedded")]
2245pub async fn write_v1_msg_async<M: Message>(
2246    w: &mut impl embedded_io_async::Write,
2247    header: MavHeader,
2248    data: &M,
2249) -> Result<usize, MessageWriteError> {
2250    if data.message_id() > u8::MAX.into() {
2251        return Err(MessageWriteError::MAVLink2Only);
2252    }
2253    let mut message_raw = MAVLinkV1MessageRaw::new();
2254    message_raw.serialize_message(header, data);
2255
2256    let payload_length: usize = message_raw.payload_length().into();
2257    let len = 1 + MAVLinkV1MessageRaw::HEADER_SIZE + payload_length + 2;
2258
2259    w.write_all(&message_raw.0[..len])
2260        .await
2261        .map_err(|_| MessageWriteError::Io)?;
2262
2263    Ok(len)
2264}
2265
2266#[deprecated = "use read_versioned_raw_message instead"]
2267pub fn read_raw_versioned_msg<M: Message, R: Read>(
2268    r: &mut PeekReader<R>,
2269    version: ReadVersion,
2270) -> Result<MAVLinkMessageRaw, MessageReadError> {
2271    read_versioned_raw_message::<M, _>(r, version)
2272}
2273
2274#[cfg(feature = "tokio-1")]
2275#[deprecated = "use read_versioned_raw_message_async instead"]
2276pub async fn read_raw_versioned_msg_async<M: Message, R: tokio::io::AsyncRead + Unpin>(
2277    r: &mut AsyncPeekReader<R>,
2278    version: ReadVersion,
2279) -> Result<MAVLinkMessageRaw, MessageReadError> {
2280    read_versioned_raw_message_async::<M, _>(r, version).await
2281}
2282
2283#[cfg(feature = "signing")]
2284#[deprecated = "use read_versioned_raw_message_signed instead"]
2285pub fn read_raw_versioned_msg_signed<M: Message, R: Read>(
2286    r: &mut PeekReader<R>,
2287    version: ReadVersion,
2288    signing_data: Option<&SigningData>,
2289) -> Result<MAVLinkMessageRaw, MessageReadError> {
2290    read_versioned_raw_message_signed::<M, _>(r, version, signing_data)
2291}
2292
2293#[cfg(all(feature = "tokio-1", feature = "signing"))]
2294#[deprecated = "use read_versioned_raw_message_async_signed instead"]
2295pub async fn read_raw_versioned_msg_async_signed<M: Message, R: tokio::io::AsyncRead + Unpin>(
2296    r: &mut AsyncPeekReader<R>,
2297    version: ReadVersion,
2298    signing_data: Option<&SigningData>,
2299) -> Result<MAVLinkMessageRaw, MessageReadError> {
2300    read_versioned_raw_message_async_signed::<M, _>(r, version, signing_data).await
2301}