use crate::{
MAVLinkMessageRaw, MavHeader, MavlinkVersion, Message,
error::MessageReadError,
frame_decoder::{FrameDecoder, VersionFilter},
reader::{try_decode_message, try_decode_raw_message},
static_dialect::StaticDialect,
};
#[cfg(feature = "tokio")]
use crate::{Dialect, SigningData};
#[cfg(all(feature = "embedded", not(feature = "std")))]
use embedded_io_async::Read;
#[cfg(feature = "tokio")]
use tokio::io::{AsyncRead, AsyncReadExt};
pub struct AsyncMavlinkReader<R> {
source: R,
decoder: FrameDecoder,
}
impl<R> AsyncMavlinkReader<R> {
#[cfg(feature = "std")]
pub fn new(source: R) -> Self
where
R: AsyncRead + Unpin,
{
Self {
source,
decoder: FrameDecoder::new(),
}
}
#[cfg(not(feature = "std"))]
pub const fn new(source: R) -> Self
where
R: Read,
{
Self {
source,
decoder: FrameDecoder::new(),
}
}
#[cfg(feature = "std")]
pub fn with_capacity(capacity: usize, source: R) -> Self
where
R: AsyncRead + Unpin,
{
Self {
source,
decoder: FrameDecoder::with_capacity(capacity),
}
}
pub const fn get_ref(&self) -> &R {
&self.source
}
pub const fn get_mut(&mut self) -> &mut R {
&mut self.source
}
pub fn into_inner(self) -> R {
self.source
}
}
#[cfg(feature = "tokio")]
impl<R: AsyncRead + Unpin> AsyncMavlinkReader<R> {
pub async fn read_message<M: Message>(
&mut self,
version: MavlinkVersion,
) -> Result<(MavHeader, M), MessageReadError> {
self.read_message_inner(VersionFilter::Exact(version), None)
.await
}
pub async fn read_message_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
version: MavlinkVersion,
) -> Result<(MavHeader, D::Message), MessageReadError> {
self.read_message_with_dialect_inner(VersionFilter::Exact(version), dialect, None)
.await
}
pub async fn read_any_message<M: Message>(
&mut self,
) -> Result<(MavHeader, M), MessageReadError> {
self.read_message_inner(VersionFilter::Any, None).await
}
pub async fn read_any_message_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
) -> Result<(MavHeader, D::Message), MessageReadError> {
self.read_message_with_dialect_inner(VersionFilter::Any, dialect, None)
.await
}
pub async fn read_raw_message<M: Message>(
&mut self,
version: MavlinkVersion,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_inner::<M>(VersionFilter::Exact(version), None)
.await
}
pub async fn read_raw_message_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
version: MavlinkVersion,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_with_dialect_inner(VersionFilter::Exact(version), dialect, None)
.await
}
pub async fn read_any_raw_message<M: Message>(
&mut self,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_inner::<M>(VersionFilter::Any, None)
.await
}
pub async fn read_any_raw_message_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_with_dialect_inner(VersionFilter::Any, dialect, None)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_message_signed<M: Message>(
&mut self,
version: MavlinkVersion,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, M), MessageReadError> {
self.read_message_inner(VersionFilter::Exact(version), signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_message_signed_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
version: MavlinkVersion,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, D::Message), MessageReadError> {
self.read_message_with_dialect_inner(VersionFilter::Exact(version), dialect, signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_any_message_signed<M: Message>(
&mut self,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, M), MessageReadError> {
self.read_message_inner(VersionFilter::Any, signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_any_message_signed_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, D::Message), MessageReadError> {
self.read_message_with_dialect_inner(VersionFilter::Any, dialect, signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_raw_message_signed<M: Message>(
&mut self,
version: MavlinkVersion,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_inner::<M>(VersionFilter::Exact(version), signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_raw_message_signed_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
version: MavlinkVersion,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_with_dialect_inner(
VersionFilter::Exact(version),
dialect,
signing_data,
)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_any_raw_message_signed<M: Message>(
&mut self,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_inner::<M>(VersionFilter::Any, signing_data)
.await
}
#[cfg(feature = "mav2-message-signing")]
pub async fn read_any_raw_message_signed_with_dialect<D: Dialect>(
&mut self,
dialect: &D,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_with_dialect_inner(VersionFilter::Any, dialect, signing_data)
.await
}
#[inline]
pub(crate) async fn read_message_inner<M: Message>(
&mut self,
filter: VersionFilter,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, M), MessageReadError> {
self.read_message_with_dialect_inner(filter, &StaticDialect::<M>::new(), signing_data)
.await
}
#[inline]
pub(crate) async fn read_message_with_dialect_inner<D: Dialect>(
&mut self,
filter: VersionFilter,
dialect: &D,
signing_data: Option<&SigningData>,
) -> Result<(MavHeader, D::Message), MessageReadError> {
loop {
if let Some(result) =
try_decode_message(&mut self.decoder, filter, dialect, signing_data)
{
return result;
}
self.read_more().await?;
}
}
#[inline]
pub(crate) async fn read_raw_message_inner<M: Message>(
&mut self,
filter: VersionFilter,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
self.read_raw_message_with_dialect_inner(filter, &StaticDialect::<M>::new(), signing_data)
.await
}
#[inline]
pub(crate) async fn read_raw_message_with_dialect_inner<D: Dialect>(
&mut self,
filter: VersionFilter,
dialect: &D,
signing_data: Option<&SigningData>,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
loop {
if let Some(message) =
try_decode_raw_message(&mut self.decoder, filter, dialect, signing_data)
{
return Ok(message);
}
self.read_more().await?;
}
}
async fn read_more(&mut self) -> Result<(), MessageReadError> {
let destination = self.decoder.spare_capacity_mut();
assert!(
!destination.is_empty(),
"a pending MAVLink frame must fit in the decoder buffer"
);
let count = loop {
match self.source.read(destination).await {
Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
result => break result?,
}
};
if count == 0 {
return Err(MessageReadError::eof());
}
self.decoder.commit(count);
Ok(())
}
}
#[cfg(all(feature = "embedded", not(feature = "std")))]
impl<R: Read> AsyncMavlinkReader<R> {
pub async fn read_message<M: Message>(
&mut self,
version: MavlinkVersion,
) -> Result<(MavHeader, M), MessageReadError> {
let filter = VersionFilter::Exact(version);
loop {
if let Some(result) =
try_decode_message(&mut self.decoder, filter, &StaticDialect::<M>::new(), None)
{
return result;
}
self.read_more().await?;
}
}
pub async fn read_any_message<M: Message>(
&mut self,
) -> Result<(MavHeader, M), MessageReadError> {
loop {
if let Some(result) = try_decode_message(
&mut self.decoder,
VersionFilter::Any,
&StaticDialect::<M>::new(),
None,
) {
return result;
}
self.read_more().await?;
}
}
pub async fn read_raw_message<M: Message>(
&mut self,
version: MavlinkVersion,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
let filter = VersionFilter::Exact(version);
loop {
if let Some(message) =
try_decode_raw_message(&mut self.decoder, filter, &StaticDialect::<M>::new(), None)
{
return Ok(message);
}
self.read_more().await?;
}
}
pub async fn read_any_raw_message<M: Message>(
&mut self,
) -> Result<MAVLinkMessageRaw, MessageReadError> {
loop {
if let Some(message) = try_decode_raw_message(
&mut self.decoder,
VersionFilter::Any,
&StaticDialect::<M>::new(),
None,
) {
return Ok(message);
}
self.read_more().await?;
}
}
async fn read_more(&mut self) -> Result<(), MessageReadError> {
let destination = self.decoder.spare_capacity_mut();
assert!(
!destination.is_empty(),
"a pending MAVLink frame must fit in the decoder buffer"
);
let count = self
.source
.read(destination)
.await
.map_err(|_| MessageReadError::Io)?;
if count == 0 {
return Err(MessageReadError::eof());
}
self.decoder.commit(count);
Ok(())
}
}