1use core::fmt::Display;
2use core::marker::PhantomData;
3use std::io;
4
5#[cfg(feature = "transport-tcp")]
6use super::tcp::TcpConnection;
7
8#[cfg(feature = "transport-udp")]
9use super::udp::UdpConnection;
10
11#[cfg(feature = "transport-direct-serial")]
12use super::direct_serial::SerialConnection;
13
14use super::file::FileConnection;
15
16#[cfg(feature = "mav2-message-signing")]
17use crate::SigningConfig;
18
19use crate::error::MessageReadError;
20use crate::error::MessageWriteError;
21use crate::{
22 MAVLinkMessageRaw, MavFrame, MavHeader, MavlinkVersion, Message, connectable::ConnectionAddress,
23};
24
25pub trait MavConnection<M: Message> {
27 fn recv(&self) -> Result<(MavHeader, M), MessageReadError>;
36
37 fn recv_raw(&self) -> Result<MAVLinkMessageRaw, MessageReadError>;
46
47 fn try_recv(&self) -> Result<(MavHeader, M), MessageReadError>;
56
57 fn send(&self, header: &MavHeader, data: &M) -> Result<usize, MessageWriteError>;
63
64 fn send_raw(&self, data: &MAVLinkMessageRaw) -> Result<usize, MessageWriteError>;
70
71 fn set_protocol_version(&mut self, version: MavlinkVersion);
73 fn protocol_version(&self) -> MavlinkVersion;
75
76 fn set_allow_recv_any_version(&mut self, allow: bool);
80
81 fn allow_recv_any_version(&self) -> bool;
83
84 fn send_frame(&self, frame: &MavFrame<M>) -> Result<usize, MessageWriteError> {
90 self.send(&frame.header, &frame.msg)
91 }
92
93 fn recv_frame(&self) -> Result<MavFrame<M>, MessageReadError> {
99 let (header, msg) = self.recv()?;
100 let protocol_version = self.protocol_version();
101 Ok(MavFrame {
102 header,
103 msg,
104 protocol_version,
105 })
106 }
107
108 fn send_default(&self, data: &M) -> Result<usize, MessageWriteError> {
114 let header = MavHeader::default();
115 self.send(&header, data)
116 }
117
118 #[cfg(feature = "mav2-message-signing")]
120 fn setup_signing(&mut self, signing_data: Option<SigningConfig>);
121}
122
123pub struct Connection<M: Message> {
125 inner: ConnectionInner,
126 _p: PhantomData<M>,
127}
128
129enum ConnectionInner {
130 #[cfg(feature = "transport-tcp")]
131 Tcp(TcpConnection),
132 #[cfg(feature = "transport-udp")]
133 Udp(UdpConnection),
134 #[cfg(feature = "transport-direct-serial")]
135 Serial(SerialConnection),
136 File(FileConnection),
137}
138
139impl<M: Message> Connection<M> {
140 fn new(inner: ConnectionInner) -> Self {
141 Self {
142 inner,
143 _p: PhantomData,
144 }
145 }
146}
147
148#[cfg(feature = "transport-tcp")]
149impl<M: Message> From<TcpConnection> for Connection<M> {
150 fn from(value: TcpConnection) -> Self {
151 Self::new(ConnectionInner::Tcp(value))
152 }
153}
154
155#[cfg(feature = "transport-udp")]
156impl<M: Message> From<UdpConnection> for Connection<M> {
157 fn from(value: UdpConnection) -> Self {
158 Self::new(ConnectionInner::Udp(value))
159 }
160}
161
162#[cfg(feature = "transport-direct-serial")]
163impl<M: Message> From<SerialConnection> for Connection<M> {
164 fn from(value: SerialConnection) -> Self {
165 Self::new(ConnectionInner::Serial(value))
166 }
167}
168
169impl<M: Message> From<FileConnection> for Connection<M> {
170 fn from(value: FileConnection) -> Self {
171 Self::new(ConnectionInner::File(value))
172 }
173}
174
175impl<M: Message> MavConnection<M> for Connection<M> {
176 fn recv(&self) -> Result<(MavHeader, M), MessageReadError> {
177 match &self.inner {
178 #[cfg(feature = "transport-tcp")]
179 ConnectionInner::Tcp(conn) => <TcpConnection as MavConnection<M>>::recv(conn),
180 #[cfg(feature = "transport-udp")]
181 ConnectionInner::Udp(conn) => <UdpConnection as MavConnection<M>>::recv(conn),
182 #[cfg(feature = "transport-direct-serial")]
183 ConnectionInner::Serial(conn) => <SerialConnection as MavConnection<M>>::recv(conn),
184 ConnectionInner::File(conn) => <FileConnection as MavConnection<M>>::recv(conn),
185 }
186 }
187
188 fn recv_raw(&self) -> Result<MAVLinkMessageRaw, MessageReadError> {
189 match &self.inner {
190 #[cfg(feature = "transport-tcp")]
191 ConnectionInner::Tcp(conn) => <TcpConnection as MavConnection<M>>::recv_raw(conn),
192 #[cfg(feature = "transport-udp")]
193 ConnectionInner::Udp(conn) => <UdpConnection as MavConnection<M>>::recv_raw(conn),
194 #[cfg(feature = "transport-direct-serial")]
195 ConnectionInner::Serial(conn) => <SerialConnection as MavConnection<M>>::recv_raw(conn),
196 ConnectionInner::File(conn) => <FileConnection as MavConnection<M>>::recv_raw(conn),
197 }
198 }
199
200 fn try_recv(&self) -> Result<(MavHeader, M), MessageReadError> {
201 match &self.inner {
202 #[cfg(feature = "transport-tcp")]
203 ConnectionInner::Tcp(conn) => <TcpConnection as MavConnection<M>>::try_recv(conn),
204 #[cfg(feature = "transport-udp")]
205 ConnectionInner::Udp(conn) => <UdpConnection as MavConnection<M>>::try_recv(conn),
206 #[cfg(feature = "transport-direct-serial")]
207 ConnectionInner::Serial(conn) => <SerialConnection as MavConnection<M>>::try_recv(conn),
208 ConnectionInner::File(conn) => <FileConnection as MavConnection<M>>::try_recv(conn),
209 }
210 }
211
212 fn send(&self, header: &MavHeader, data: &M) -> Result<usize, MessageWriteError> {
213 match &self.inner {
214 #[cfg(feature = "transport-tcp")]
215 ConnectionInner::Tcp(conn) => {
216 <TcpConnection as MavConnection<M>>::send(conn, header, data)
217 }
218 #[cfg(feature = "transport-udp")]
219 ConnectionInner::Udp(conn) => {
220 <UdpConnection as MavConnection<M>>::send(conn, header, data)
221 }
222 #[cfg(feature = "transport-direct-serial")]
223 ConnectionInner::Serial(conn) => {
224 <SerialConnection as MavConnection<M>>::send(conn, header, data)
225 }
226 ConnectionInner::File(conn) => {
227 <FileConnection as MavConnection<M>>::send(conn, header, data)
228 }
229 }
230 }
231
232 fn send_raw(&self, data: &MAVLinkMessageRaw) -> Result<usize, MessageWriteError> {
233 match &self.inner {
234 #[cfg(feature = "transport-tcp")]
235 ConnectionInner::Tcp(conn) => <TcpConnection as MavConnection<M>>::send_raw(conn, data),
236 #[cfg(feature = "transport-udp")]
237 ConnectionInner::Udp(conn) => <UdpConnection as MavConnection<M>>::send_raw(conn, data),
238 #[cfg(feature = "transport-direct-serial")]
239 ConnectionInner::Serial(conn) => {
240 <SerialConnection as MavConnection<M>>::send_raw(conn, data)
241 }
242 ConnectionInner::File(conn) => {
243 <FileConnection as MavConnection<M>>::send_raw(conn, data)
244 }
245 }
246 }
247
248 fn set_protocol_version(&mut self, version: MavlinkVersion) {
249 match &mut self.inner {
250 #[cfg(feature = "transport-tcp")]
251 ConnectionInner::Tcp(conn) => {
252 <TcpConnection as MavConnection<M>>::set_protocol_version(conn, version);
253 }
254 #[cfg(feature = "transport-udp")]
255 ConnectionInner::Udp(conn) => {
256 <UdpConnection as MavConnection<M>>::set_protocol_version(conn, version);
257 }
258 #[cfg(feature = "transport-direct-serial")]
259 ConnectionInner::Serial(conn) => {
260 <SerialConnection as MavConnection<M>>::set_protocol_version(conn, version);
261 }
262 ConnectionInner::File(conn) => {
263 <FileConnection as MavConnection<M>>::set_protocol_version(conn, version);
264 }
265 }
266 }
267
268 fn protocol_version(&self) -> MavlinkVersion {
269 match &self.inner {
270 #[cfg(feature = "transport-tcp")]
271 ConnectionInner::Tcp(conn) => {
272 <TcpConnection as MavConnection<M>>::protocol_version(conn)
273 }
274 #[cfg(feature = "transport-udp")]
275 ConnectionInner::Udp(conn) => {
276 <UdpConnection as MavConnection<M>>::protocol_version(conn)
277 }
278 #[cfg(feature = "transport-direct-serial")]
279 ConnectionInner::Serial(conn) => {
280 <SerialConnection as MavConnection<M>>::protocol_version(conn)
281 }
282 ConnectionInner::File(conn) => {
283 <FileConnection as MavConnection<M>>::protocol_version(conn)
284 }
285 }
286 }
287
288 fn set_allow_recv_any_version(&mut self, allow: bool) {
289 match &mut self.inner {
290 #[cfg(feature = "transport-tcp")]
291 ConnectionInner::Tcp(conn) => {
292 <TcpConnection as MavConnection<M>>::set_allow_recv_any_version(conn, allow);
293 }
294 #[cfg(feature = "transport-udp")]
295 ConnectionInner::Udp(conn) => {
296 <UdpConnection as MavConnection<M>>::set_allow_recv_any_version(conn, allow);
297 }
298 #[cfg(feature = "transport-direct-serial")]
299 ConnectionInner::Serial(conn) => {
300 <SerialConnection as MavConnection<M>>::set_allow_recv_any_version(conn, allow);
301 }
302 ConnectionInner::File(conn) => {
303 <FileConnection as MavConnection<M>>::set_allow_recv_any_version(conn, allow);
304 }
305 }
306 }
307
308 fn allow_recv_any_version(&self) -> bool {
309 match &self.inner {
310 #[cfg(feature = "transport-tcp")]
311 ConnectionInner::Tcp(conn) => {
312 <TcpConnection as MavConnection<M>>::allow_recv_any_version(conn)
313 }
314 #[cfg(feature = "transport-udp")]
315 ConnectionInner::Udp(conn) => {
316 <UdpConnection as MavConnection<M>>::allow_recv_any_version(conn)
317 }
318 #[cfg(feature = "transport-direct-serial")]
319 ConnectionInner::Serial(conn) => {
320 <SerialConnection as MavConnection<M>>::allow_recv_any_version(conn)
321 }
322 ConnectionInner::File(conn) => {
323 <FileConnection as MavConnection<M>>::allow_recv_any_version(conn)
324 }
325 }
326 }
327
328 #[cfg(feature = "mav2-message-signing")]
329 fn setup_signing(&mut self, signing_data: Option<SigningConfig>) {
330 let mut signing_data = signing_data;
331 match &mut self.inner {
332 #[cfg(feature = "transport-tcp")]
333 ConnectionInner::Tcp(conn) => {
334 <TcpConnection as MavConnection<M>>::setup_signing(conn, signing_data.take());
335 }
336 #[cfg(feature = "transport-udp")]
337 ConnectionInner::Udp(conn) => {
338 <UdpConnection as MavConnection<M>>::setup_signing(conn, signing_data.take());
339 }
340 #[cfg(feature = "transport-direct-serial")]
341 ConnectionInner::Serial(conn) => {
342 <SerialConnection as MavConnection<M>>::setup_signing(conn, signing_data.take());
343 }
344 ConnectionInner::File(conn) => {
345 <FileConnection as MavConnection<M>>::setup_signing(conn, signing_data.take());
346 }
347 }
348 }
349}
350
351pub fn connect<M: Message + Sync + Send>(address: &str) -> io::Result<Connection<M>> {
373 ConnectionAddress::parse_address(address)?.connect::<M>()
374}
375
376pub trait Connectable: Display {
378 fn connect<M: Message>(&self) -> io::Result<Connection<M>>;
385}
386
387impl Connectable for ConnectionAddress {
388 fn connect<M>(&self) -> std::io::Result<Connection<M>>
389 where
390 M: Message,
391 {
392 match self {
393 #[cfg(feature = "transport-tcp")]
394 Self::Tcp(config) => config.connect::<M>(),
395 #[cfg(feature = "transport-udp")]
396 Self::Udp(config) => config.connect::<M>(),
397 #[cfg(feature = "transport-direct-serial")]
398 Self::Serial(config) => config.connect::<M>(),
399 Self::File(config) => config.connect::<M>(),
400 }
401 }
402}