Skip to main content

mavlink_core/connection/
async.rs

1use std::io;
2
3use async_trait::async_trait;
4
5#[cfg(feature = "mav2-message-signing")]
6use crate::SigningConfig;
7
8use crate::error::MessageReadError;
9use crate::error::MessageWriteError;
10use crate::{
11    MAVLinkMessageRaw, MavFrame, MavHeader, MavlinkVersion, Message, connectable::ConnectionAddress,
12};
13
14/// An async MAVLink connection
15#[async_trait]
16pub trait AsyncMavConnection<M: Message + Sync + Send> {
17    /// Receive a mavlink message.
18    ///
19    /// Yield until a valid frame is received, ignoring invalid messages.
20    async fn recv(&self) -> Result<(MavHeader, M), MessageReadError>;
21
22    /// Receive a raw, unparsed mavlink message.
23    ///
24    /// Yield until a valid frame is received, ignoring invalid messages.
25    async fn recv_raw(&self) -> Result<MAVLinkMessageRaw, MessageReadError>;
26
27    /// Try to receive a MAVLink message.
28    ///
29    /// Non-blocking variant of `recv()`, returns immediately with a `MessageReadError`
30    /// if there is an error or no message is available.
31    ///
32    /// # Errors
33    ///
34    /// Returns any eror encounter while receiving or deserializing a message.
35    async fn try_recv(&self) -> Result<(MavHeader, M), MessageReadError>;
36
37    /// Send a mavlink message
38    async fn send(&self, header: &MavHeader, data: &M) -> Result<usize, MessageWriteError>;
39
40    /// Send a raw, unparsed mavlink message
41    async fn send_raw(&self, data: &MAVLinkMessageRaw) -> Result<usize, MessageWriteError>;
42
43    /// Sets the MAVLink version to use for receiving (when `allow_recv_any_version()` is `false`) and sending messages.
44    fn set_protocol_version(&mut self, version: MavlinkVersion);
45    /// Gets the currently used MAVLink version
46    fn protocol_version(&self) -> MavlinkVersion;
47
48    /// Set wether MAVLink messages of either version may be received.
49    ///
50    /// If set to false only messages of the version configured with `set_protocol_version()` are received.
51    fn set_allow_recv_any_version(&mut self, allow: bool);
52
53    /// Wether messages of any MAVLink version may be received.
54    fn allow_recv_any_version(&self) -> bool;
55
56    /// Write whole frame.
57    async fn send_frame(&self, frame: &MavFrame<M>) -> Result<usize, MessageWriteError> {
58        self.send(&frame.header, &frame.msg).await
59    }
60
61    /// Read whole frame.
62    async fn recv_frame(&self) -> Result<MavFrame<M>, MessageReadError> {
63        let (header, msg) = self.recv().await?;
64        let protocol_version = self.protocol_version();
65        Ok(MavFrame {
66            header,
67            msg,
68            protocol_version,
69        })
70    }
71
72    /// Send a message with default header.
73    async fn send_default(&self, data: &M) -> Result<usize, MessageWriteError> {
74        let header = MavHeader::default();
75        self.send(&header, data).await
76    }
77
78    /// Setup secret key used for message signing, or disable message signing.
79    #[cfg(feature = "mav2-message-signing")]
80    fn setup_signing(&mut self, signing_data: Option<SigningConfig>);
81}
82
83/// Connect asynchronously to a MAVLink node by address string.
84///
85/// The address must be in one of the following formats:
86///
87///  * `tcpin:<addr>:<port>` to create a TCP server, listening for an incoming connection
88///  * `tcpout:<addr>:<port>` to create a TCP client
89///  * `udpin:<addr>:<port>` to create a UDP server, listening for incoming packets
90///  * `udpout:<addr>:<port>` to create a UDP client
91///  * `udpbcast:<addr>:<port>` to create a UDP broadcast
92///  * `serial:<port>:<baudrate>` to create a serial connection
93///  * `file:<path>` to extract file data, writing to such a connection does nothing
94///
95/// The type of the connection is determined at runtime based on the address type, so the
96/// connection is returned as a trait object.
97///
98/// # Errors
99///
100/// - [`AddrNotAvailable`] if the address string could not be parsed as a valid MAVLink address
101/// - When the connection could not be established a corresponding [`io::Error`] is returned
102///
103/// [`AddrNotAvailable`]: io::ErrorKind::AddrNotAvailable
104pub async fn connect_async<M: Message + Sync + Send>(
105    address: &str,
106) -> io::Result<Box<dyn AsyncMavConnection<M> + Sync + Send>> {
107    ConnectionAddress::parse_address(address)?
108        .connect_async::<M>()
109        .await
110}
111
112/// A MAVLink connection address that can be connected to, establishing an [`AsyncMavConnection`]
113///
114/// This is the `async` version of `Connectable`.
115#[async_trait]
116pub trait AsyncConnectable {
117    /// Attempt to establish an asynchronous MAVLink connection
118    async fn connect_async<M>(&self) -> io::Result<Box<dyn AsyncMavConnection<M> + Sync + Send>>
119    where
120        M: Message + Sync + Send;
121}
122
123#[async_trait]
124impl AsyncConnectable for ConnectionAddress {
125    async fn connect_async<M>(&self) -> io::Result<Box<dyn AsyncMavConnection<M> + Sync + Send>>
126    where
127        M: Message + Sync + Send,
128    {
129        match self {
130            #[cfg(feature = "transport-tcp")]
131            Self::Tcp(connectable) => connectable.connect_async::<M>().await,
132            #[cfg(feature = "transport-udp")]
133            Self::Udp(connectable) => connectable.connect_async::<M>().await,
134            #[cfg(feature = "transport-direct-serial")]
135            Self::Serial(connectable) => connectable.connect_async::<M>().await,
136            Self::File(connectable) => connectable.connect_async::<M>().await,
137        }
138    }
139}