#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(clippy::all)]
#![warn(clippy::use_self)]
use core::result::Result;
#[cfg(feature = "std")]
use std::io::Write;
pub mod utils;
#[allow(unused_imports)]
use utils::{RustDefault, remove_trailing_zeroes};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::frame_decoder::FrameRef;
use crate::{
bytes::Bytes,
error::{MessageWriteError, ParserError},
};
use crc_any::CRCu16;
#[doc(hidden)]
pub mod bytes;
#[doc(hidden)]
pub mod bytes_mut;
#[cfg(any(feature = "std", feature = "tokio"))]
mod connection;
pub mod consts;
pub mod error;
mod frame_decoder;
mod reader;
pub mod types;
#[cfg(feature = "std")]
pub use self::connection::{Connectable, Connection, MavConnection, connect};
pub use reader::MavlinkReader;
#[cfg(feature = "tokio")]
pub use self::connection::{AsyncConnectable, AsyncMavConnection, connect_async};
#[cfg(feature = "tokio")]
use tokio::io::{AsyncWrite, AsyncWriteExt};
#[cfg(any(feature = "tokio", all(feature = "embedded", not(feature = "std"))))]
mod async_reader;
#[cfg(any(feature = "tokio", all(feature = "embedded", not(feature = "std"))))]
pub use async_reader::AsyncMavlinkReader;
#[cfg(all(feature = "embedded", not(feature = "std")))]
pub mod embedded;
#[cfg(all(feature = "embedded", not(feature = "std")))]
use embedded::Write;
#[cfg(not(feature = "mav2-message-signing"))]
type SigningData = ();
#[cfg(feature = "mav2-message-signing")]
mod signing;
#[cfg(feature = "mav2-message-signing")]
pub use self::signing::{SigningConfig, SigningData};
#[cfg(feature = "mav2-message-signing")]
use sha2::{Digest, Sha256};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[cfg(any(feature = "std", feature = "tokio"))]
mod connectable;
#[cfg(any(feature = "std", feature = "tokio"))]
mod connection_shared;
#[cfg(any(feature = "std", feature = "tokio"))]
pub use connectable::ConnectionAddress;
#[cfg(feature = "transport-direct-serial")]
pub use connection::direct_serial::config::SerialConfig;
#[cfg(feature = "transport-tcp")]
pub use connection::tcp::config::{TcpConfig, TcpMode};
#[cfg(feature = "transport-udp")]
pub use connection::udp::config::{UdpConfig, UdpMode};
#[cfg(feature = "std")]
pub use connection::file::config::FileConfig;
pub trait Message
where
Self: Sized,
{
fn message_id(&self) -> u32;
fn message_name(&self) -> &'static str;
fn target_system_id(&self) -> Option<u8>;
fn target_component_id(&self) -> Option<u8>;
fn ser(&self, version: MavlinkVersion, bytes: &mut [u8]) -> usize;
fn parse(version: MavlinkVersion, msgid: u32, payload: &[u8]) -> Result<Self, ParserError>;
fn message_id_from_name(name: &str) -> Option<u32>;
fn default_message_from_id(id: u32) -> Option<Self>;
#[cfg(feature = "arbitrary")]
fn random_message_from_id<R: rand::TryRng<Error = std::convert::Infallible>>(
id: u32,
rng: &mut R,
) -> Option<Self>;
fn extra_crc(id: u32) -> u8;
}
pub trait MessageData: Sized {
type Message: Message;
const ID: u32;
const NAME: &'static str;
const EXTRA_CRC: u8;
const ENCODED_LEN: usize;
fn ser(&self, version: MavlinkVersion, payload: &mut [u8]) -> usize;
fn deser(version: MavlinkVersion, payload: &[u8]) -> Result<Self, ParserError>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct MavHeader {
pub system_id: u8,
pub component_id: u8,
pub sequence: u8,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type"))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum MavlinkVersion {
V1,
V2,
}
pub const MAV_STX: u8 = 0xFE;
pub const MAV_STX_V2: u8 = 0xFD;
impl Default for MavHeader {
fn default() -> Self {
Self {
system_id: 255,
component_id: 0,
sequence: 0,
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct MavFrame<M: Message> {
pub header: MavHeader,
pub msg: M,
pub protocol_version: MavlinkVersion,
}
impl<M: Message> MavFrame<M> {
pub fn ser(&self, buf: &mut [u8]) -> usize {
let mut buf = bytes_mut::BytesMut::new(buf);
buf.put_slice(&[
self.header.sequence,
self.header.system_id,
self.header.component_id,
]);
match self.protocol_version {
MavlinkVersion::V2 => buf.put_u24_le(self.msg.message_id()),
MavlinkVersion::V1 => buf.put_u8(
self.msg
.message_id()
.try_into()
.expect("message is MAVLink 2 only"),
),
}
let header_len = buf.len();
let payload_len = self.msg.ser(self.protocol_version, &mut buf[header_len..]);
header_len + payload_len
}
pub fn deser(version: MavlinkVersion, input: &[u8]) -> Result<Self, ParserError> {
let mut buf = Bytes::new(input);
let sequence = buf.get_u8()?;
let system_id = buf.get_u8()?;
let component_id = buf.get_u8()?;
let header = MavHeader {
system_id,
component_id,
sequence,
};
let msg_id = match version {
MavlinkVersion::V2 => buf.get_u24_le()?,
MavlinkVersion::V1 => buf.get_u8()?.into(),
};
M::parse(version, msg_id, buf.remaining_bytes()).map(|msg| Self {
header,
msg,
protocol_version: version,
})
}
pub fn header(&self) -> MavHeader {
self.header
}
}
pub fn calculate_crc(data: &[u8], extra_crc: u8) -> u16 {
let mut crc_calculator = CRCu16::crc16mcrf4cc();
crc_calculator.digest(data);
crc_calculator.digest(&[extra_crc]);
crc_calculator.get_crc()
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct MAVLinkV1MessageRaw([u8; consts::v1::FRAME_SIZE]);
impl MAVLinkV1MessageRaw {
pub const fn new() -> Self {
Self([0; consts::v1::FRAME_SIZE])
}
pub const fn from_bytes_unparsed(bytes: [u8; consts::v1::FRAME_SIZE]) -> Self {
Self(bytes)
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
#[inline]
pub fn into_inner(self) -> [u8; consts::v1::FRAME_SIZE] {
self.0
}
#[inline]
pub fn header(&self) -> &[u8] {
&self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE)]
}
#[inline]
fn mut_header(&mut self) -> &mut [u8] {
&mut self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE)]
}
#[inline]
pub fn payload_length(&self) -> u8 {
self.0[consts::PAYLOAD_LEN_OFFSET]
}
#[inline]
pub fn sequence(&self) -> u8 {
self.0[2]
}
#[inline]
pub fn system_id(&self) -> u8 {
self.0[3]
}
#[inline]
pub fn component_id(&self) -> u8 {
self.0[4]
}
#[inline]
pub fn message_id(&self) -> u8 {
self.0[5]
}
#[inline]
pub fn payload(&self) -> &[u8] {
let payload_length: usize = self.payload_length().into();
let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
&self.0[payload_offset..(payload_offset + payload_length)]
}
#[inline]
pub fn checksum(&self) -> u16 {
let payload_length: usize = self.payload_length().into();
let checksum_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length;
u16::from_le_bytes([self.0[checksum_offset], self.0[checksum_offset + 1]])
}
#[inline]
pub fn has_valid_crc<M: Message>(&self) -> bool {
let payload_length: usize = self.payload_length().into();
let crc_end = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length;
self.checksum()
== calculate_crc(
&self.0[consts::STX_SIZE..crc_end],
M::extra_crc(self.message_id().into()),
)
}
pub fn raw_bytes(&self) -> &[u8] {
let payload_length = self.payload_length() as usize;
let frame_len =
consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
&self.0[..frame_len]
}
fn serialize_stx_and_header_and_crc(
&mut self,
header: MavHeader,
msgid: u32,
payload_length: usize,
extra_crc: u8,
) {
self.0[consts::STX_OFFSET] = MAV_STX;
let header_buf = self.mut_header();
header_buf.copy_from_slice(&[
payload_length as u8,
header.sequence,
header.system_id,
header.component_id,
msgid.try_into().unwrap(),
]);
let crc = calculate_crc(
&self.0
[consts::STX_SIZE..(consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length)],
extra_crc,
);
self.0[(consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length)
..(consts::STX_SIZE
+ consts::v1::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE)]
.copy_from_slice(&crc.to_le_bytes());
}
pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
let payload_length = message.ser(MavlinkVersion::V1, payload_buf);
let message_id = message.message_id();
self.serialize_stx_and_header_and_crc(
header,
message_id,
payload_length,
M::extra_crc(message_id),
);
}
pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
let payload_offset = consts::STX_SIZE + consts::v1::HEADER_SIZE;
let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
let payload_length = message_data.ser(MavlinkVersion::V1, payload_buf);
self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC);
}
}
impl Default for MAVLinkV1MessageRaw {
fn default() -> Self {
Self::new()
}
}
impl<'a> From<FrameRef<'a>> for MAVLinkV1MessageRaw {
fn from(frame: FrameRef<'a>) -> Self {
let mut message = Self::new();
message.0[..frame.bytes().len()].copy_from_slice(frame.bytes());
message
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct MAVLinkV2MessageRaw([u8; consts::MAX_FRAME_SIZE]);
impl MAVLinkV2MessageRaw {
pub const fn new() -> Self {
Self([0; consts::MAX_FRAME_SIZE])
}
pub const fn from_bytes_unparsed(bytes: [u8; consts::MAX_FRAME_SIZE]) -> Self {
Self(bytes)
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
#[inline]
pub fn into_inner(self) -> [u8; consts::MAX_FRAME_SIZE] {
self.0
}
#[inline]
pub fn header(&self) -> &[u8] {
&self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE)]
}
#[inline]
fn mut_header(&mut self) -> &mut [u8] {
&mut self.0[consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE)]
}
#[inline]
pub fn payload_length(&self) -> u8 {
self.0[consts::PAYLOAD_LEN_OFFSET]
}
#[inline]
pub fn incompatibility_flags(&self) -> u8 {
self.0[consts::v2::INCOMPAT_FLAGS_OFFSET]
}
#[inline]
pub fn incompatibility_flags_mut(&mut self) -> &mut u8 {
&mut self.0[consts::v2::INCOMPAT_FLAGS_OFFSET]
}
#[inline]
pub fn compatibility_flags(&self) -> u8 {
self.0[3]
}
#[inline]
pub fn sequence(&self) -> u8 {
self.0[4]
}
#[inline]
pub fn system_id(&self) -> u8 {
self.0[5]
}
#[inline]
pub fn component_id(&self) -> u8 {
self.0[6]
}
#[inline]
pub fn message_id(&self) -> u32 {
u32::from_le_bytes([self.0[7], self.0[8], self.0[9], 0])
}
#[inline]
pub fn payload(&self) -> &[u8] {
let payload_length: usize = self.payload_length().into();
let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
&self.0[payload_offset..(payload_offset + payload_length)]
}
#[inline]
pub fn checksum(&self) -> u16 {
let payload_length: usize = self.payload_length().into();
let checksum_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length;
u16::from_le_bytes([self.0[checksum_offset], self.0[checksum_offset + 1]])
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn checksum_bytes(&self) -> &[u8] {
let checksum_offset =
consts::STX_SIZE + consts::v2::HEADER_SIZE + self.payload_length() as usize;
&self.0[checksum_offset..(checksum_offset + consts::CHECKSUM_SIZE)]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_link_id(&self) -> u8 {
let payload_length: usize = self.payload_length().into();
self.0[consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_link_id_mut(&mut self) -> &mut u8 {
let payload_length: usize = self.payload_length().into();
&mut self.0
[consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_timestamp(&self) -> u64 {
let mut timestamp_bytes = [0u8; 8];
timestamp_bytes[0..consts::v2::SIGNATURE_TIMESTAMP_SIZE]
.copy_from_slice(self.signature_timestamp_bytes());
u64::from_le_bytes(timestamp_bytes)
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_timestamp_bytes(&self) -> &[u8] {
let payload_length: usize = self.payload_length().into();
let timestamp_start = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ consts::v2::SIGNATURE_LINK_ID_SIZE;
&self.0[timestamp_start..(timestamp_start + consts::v2::SIGNATURE_TIMESTAMP_SIZE)]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_timestamp_bytes_mut(&mut self) -> &mut [u8] {
let payload_length: usize = self.payload_length().into();
let timestamp_start = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ consts::v2::SIGNATURE_LINK_ID_SIZE;
&mut self.0[timestamp_start..(timestamp_start + consts::v2::SIGNATURE_TIMESTAMP_SIZE)]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_value(&self) -> &[u8] {
let payload_length: usize = self.payload_length().into();
let signature_start = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ consts::v2::SIGNATURE_LINK_ID_SIZE
+ consts::v2::SIGNATURE_TIMESTAMP_SIZE;
&self.0[signature_start..(signature_start + consts::v2::SIGNATURE_VALUE_SIZE)]
}
#[cfg(feature = "mav2-message-signing")]
#[inline]
pub fn signature_value_mut(&mut self) -> &mut [u8] {
let payload_length: usize = self.payload_length().into();
let signature_start = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ consts::v2::SIGNATURE_LINK_ID_SIZE
+ consts::v2::SIGNATURE_TIMESTAMP_SIZE;
&mut self.0[signature_start..(signature_start + consts::v2::SIGNATURE_VALUE_SIZE)]
}
#[inline]
pub fn has_valid_crc<M: Message>(&self) -> bool {
let payload_length: usize = self.payload_length().into();
let crc_end = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length;
self.checksum()
== calculate_crc(
&self.0[consts::STX_SIZE..crc_end],
M::extra_crc(self.message_id()),
)
}
#[cfg(feature = "mav2-message-signing")]
pub fn calculate_signature(
&self,
secret_key: &[u8],
target_buffer: &mut [u8; consts::v2::SIGNATURE_VALUE_SIZE],
) {
let mut hasher = Sha256::new();
hasher.update(secret_key);
hasher.update([MAV_STX_V2]);
hasher.update(self.header());
hasher.update(self.payload());
hasher.update(self.checksum_bytes());
hasher.update([self.signature_link_id()]);
hasher.update(self.signature_timestamp_bytes());
target_buffer.copy_from_slice(&hasher.finalize()[0..consts::v2::SIGNATURE_VALUE_SIZE]);
}
pub fn raw_bytes(&self) -> &[u8] {
let payload_length = self.payload_length() as usize;
let signature_size = if (self.incompatibility_flags() & consts::v2::IFLAG_SIGNED) == 0 {
0
} else {
consts::v2::SIGNATURE_SIZE
};
let frame_len = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ signature_size
+ consts::CHECKSUM_SIZE;
&self.0[..frame_len]
}
fn serialize_stx_and_header_and_crc(
&mut self,
header: MavHeader,
msgid: u32,
payload_length: usize,
extra_crc: u8,
incompat_flags: u8,
) {
self.0[consts::STX_OFFSET] = MAV_STX_V2;
let msgid_bytes = msgid.to_le_bytes();
let header_buf = self.mut_header();
header_buf.copy_from_slice(&[
payload_length as u8,
incompat_flags,
0, header.sequence,
header.system_id,
header.component_id,
msgid_bytes[0],
msgid_bytes[1],
msgid_bytes[2],
]);
let crc = calculate_crc(
&self.0
[consts::STX_SIZE..(consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length)],
extra_crc,
);
self.0[(consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length)
..(consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE)]
.copy_from_slice(&crc.to_le_bytes());
}
pub fn serialize_message<M: Message>(&mut self, header: MavHeader, message: &M) {
let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
let message_id = message.message_id();
self.serialize_stx_and_header_and_crc(
header,
message_id,
payload_length,
M::extra_crc(message_id),
0,
);
}
pub fn serialize_message_for_signing<M: Message>(&mut self, header: MavHeader, message: &M) {
let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
let payload_length = message.ser(MavlinkVersion::V2, payload_buf);
let message_id = message.message_id();
self.serialize_stx_and_header_and_crc(
header,
message_id,
payload_length,
M::extra_crc(message_id),
consts::v2::IFLAG_SIGNED,
);
}
pub fn serialize_message_data<D: MessageData>(&mut self, header: MavHeader, message_data: &D) {
let payload_offset = consts::STX_SIZE + consts::v2::HEADER_SIZE;
let payload_buf = &mut self.0[payload_offset..(payload_offset + consts::MAX_PAYLOAD_LEN)];
let payload_length = message_data.ser(MavlinkVersion::V2, payload_buf);
self.serialize_stx_and_header_and_crc(header, D::ID, payload_length, D::EXTRA_CRC, 0);
}
}
impl Default for MAVLinkV2MessageRaw {
fn default() -> Self {
Self::new()
}
}
impl<'a> From<FrameRef<'a>> for MAVLinkV2MessageRaw {
fn from(frame: FrameRef<'a>) -> Self {
let mut message = Self::new();
message.0[..frame.bytes().len()].copy_from_slice(frame.bytes());
message
}
}
pub enum MAVLinkMessageRaw {
V1(MAVLinkV1MessageRaw),
V2(MAVLinkV2MessageRaw),
}
impl MAVLinkMessageRaw {
pub fn payload(&self) -> &[u8] {
match self {
Self::V1(msg) => msg.payload(),
Self::V2(msg) => msg.payload(),
}
}
pub fn sequence(&self) -> u8 {
match self {
Self::V1(msg) => msg.sequence(),
Self::V2(msg) => msg.sequence(),
}
}
pub fn system_id(&self) -> u8 {
match self {
Self::V1(msg) => msg.system_id(),
Self::V2(msg) => msg.system_id(),
}
}
pub fn component_id(&self) -> u8 {
match self {
Self::V1(msg) => msg.component_id(),
Self::V2(msg) => msg.component_id(),
}
}
pub fn message_id(&self) -> u32 {
match self {
Self::V1(msg) => u32::from(msg.message_id()),
Self::V2(msg) => msg.message_id(),
}
}
pub fn version(&self) -> MavlinkVersion {
match self {
Self::V1(_) => MavlinkVersion::V1,
Self::V2(_) => MavlinkVersion::V2,
}
}
}
pub fn write_versioned_msg<M: Message, W: Write>(
w: &mut W,
version: MavlinkVersion,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
match version {
MavlinkVersion::V2 => write_v2_msg(w, header, data),
MavlinkVersion::V1 => write_v1_msg(w, header, data),
}
}
#[cfg(feature = "mav2-message-signing")]
pub fn write_versioned_msg_signed<M: Message, W: Write>(
w: &mut W,
version: MavlinkVersion,
header: MavHeader,
data: &M,
signing_data: Option<&SigningData>,
) -> Result<usize, MessageWriteError> {
match version {
MavlinkVersion::V2 => write_v2_msg_signed(w, header, data, signing_data),
MavlinkVersion::V1 => write_v1_msg(w, header, data),
}
}
#[cfg(feature = "tokio")]
pub async fn write_versioned_msg_async<M: Message, W: AsyncWrite + Unpin>(
w: &mut W,
version: MavlinkVersion,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
match version {
MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
}
}
#[cfg(all(feature = "tokio", feature = "mav2-message-signing"))]
pub async fn write_versioned_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
w: &mut W,
version: MavlinkVersion,
header: MavHeader,
data: &M,
signing_data: Option<&SigningData>,
) -> Result<usize, MessageWriteError> {
match version {
MavlinkVersion::V2 => write_v2_msg_async_signed(w, header, data, signing_data).await,
MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
}
}
#[cfg(all(feature = "embedded", not(feature = "std")))]
pub async fn write_versioned_msg_async<M: Message>(
w: &mut impl embedded_io_async::Write,
version: MavlinkVersion,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
match version {
MavlinkVersion::V2 => write_v2_msg_async(w, header, data).await,
MavlinkVersion::V1 => write_v1_msg_async(w, header, data).await,
}
}
pub fn write_v2_msg<M: Message, W: Write>(
w: &mut W,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
let mut message_raw = MAVLinkV2MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len])?;
Ok(len)
}
#[cfg(feature = "mav2-message-signing")]
pub fn write_v2_msg_signed<M: Message, W: Write>(
w: &mut W,
header: MavHeader,
data: &M,
signing_data: Option<&SigningData>,
) -> Result<usize, MessageWriteError> {
let mut message_raw = MAVLinkV2MessageRaw::new();
let signature_len = if let Some(signing_data) = signing_data {
if signing_data.config.sign_outgoing {
message_raw.serialize_message_for_signing(header, data);
signing_data.sign_message(&mut message_raw);
consts::v2::SIGNATURE_SIZE
} else {
message_raw.serialize_message(header, data);
0
}
} else {
message_raw.serialize_message(header, data);
0
};
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ signature_len;
w.write_all(&message_raw.0[..len])?;
Ok(len)
}
#[cfg(feature = "tokio")]
pub async fn write_v2_msg_async<M: Message, W: AsyncWrite + Unpin>(
w: &mut W,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
let mut message_raw = MAVLinkV2MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len]).await?;
Ok(len)
}
#[cfg(feature = "mav2-message-signing")]
#[cfg(feature = "tokio")]
pub async fn write_v2_msg_async_signed<M: Message, W: AsyncWrite + Unpin>(
w: &mut W,
header: MavHeader,
data: &M,
signing_data: Option<&SigningData>,
) -> Result<usize, MessageWriteError> {
let mut message_raw = MAVLinkV2MessageRaw::new();
let signature_len = if let Some(signing_data) = signing_data {
if signing_data.config.sign_outgoing {
message_raw.serialize_message_for_signing(header, data);
signing_data.sign_message(&mut message_raw);
consts::v2::SIGNATURE_SIZE
} else {
message_raw.serialize_message(header, data);
0
}
} else {
message_raw.serialize_message(header, data);
0
};
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE
+ consts::v2::HEADER_SIZE
+ payload_length
+ consts::CHECKSUM_SIZE
+ signature_len;
w.write_all(&message_raw.0[..len]).await?;
Ok(len)
}
#[cfg(all(feature = "embedded", not(feature = "std")))]
pub async fn write_v2_msg_async<M: Message>(
w: &mut impl embedded_io_async::Write,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
let mut message_raw = MAVLinkV2MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v2::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len])
.await
.map_err(|_| MessageWriteError::Io)?;
Ok(len)
}
pub fn write_v1_msg<M: Message, W: Write>(
w: &mut W,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
if data.message_id() > u8::MAX.into() {
return Err(MessageWriteError::MAVLink2Only);
}
let mut message_raw = MAVLinkV1MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len])?;
Ok(len)
}
#[cfg(feature = "tokio")]
pub async fn write_v1_msg_async<M: Message, W: AsyncWrite + Unpin>(
w: &mut W,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
if data.message_id() > u8::MAX.into() {
return Err(MessageWriteError::MAVLink2Only);
}
let mut message_raw = MAVLinkV1MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len]).await?;
Ok(len)
}
#[cfg(all(feature = "embedded", not(feature = "std")))]
pub async fn write_v1_msg_async<M: Message>(
w: &mut impl embedded_io_async::Write,
header: MavHeader,
data: &M,
) -> Result<usize, MessageWriteError> {
if data.message_id() > u8::MAX.into() {
return Err(MessageWriteError::MAVLink2Only);
}
let mut message_raw = MAVLinkV1MessageRaw::new();
message_raw.serialize_message(header, data);
let payload_length: usize = message_raw.payload_length().into();
let len = consts::STX_SIZE + consts::v1::HEADER_SIZE + payload_length + consts::CHECKSUM_SIZE;
w.write_all(&message_raw.0[..len])
.await
.map_err(|_| MessageWriteError::Io)?;
Ok(len)
}