Skip to content

Commit 1f7c259

Browse files
committed
feat: async serial
1 parent 5f2ecbe commit 1f7c259

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

mavlink-core/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ serial = { version = "0.4", optional = true }
2929
tokio = { version = "1.0", default-features = false, features = ["io-util", "net", "sync", "fs"], optional = true }
3030
sha2 = { version = "0.10", optional = true }
3131
async-trait = { version = "0.1.18", optional = true }
32+
tokio-serial = { version = "5.4.4", default-features = false, optional = true }
3233

3334
[features]
3435
"std" = ["byteorder/std"]
@@ -41,7 +42,7 @@ async-trait = { version = "0.1.18", optional = true }
4142
"embedded" = ["dep:embedded-io", "dep:embedded-io-async"]
4243
"embedded-hal-02" = ["dep:nb", "dep:embedded-hal-02"]
4344
"serde" = ["dep:serde", "dep:serde_arrays"]
44-
"tokio-1" = ["dep:tokio", "dep:async-trait"]
45+
"tokio-1" = ["dep:tokio", "dep:async-trait", "dep:tokio-serial"]
4546
"signing" = ["dep:sha2"]
4647
default = ["std", "tcp", "udp", "direct-serial", "serde"]
4748

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! Async Serial MAVLINK connection
2+
3+
use core::ops::DerefMut;
4+
use std::io;
5+
6+
use tokio::sync::Mutex;
7+
use tokio_serial::{SerialPort, SerialPortBuilderExt, SerialStream};
8+
9+
use crate::{
10+
async_peek_reader::AsyncPeekReader, read_versioned_msg_async_signed,
11+
write_versioned_msg_async_signed, MavHeader, MavlinkVersion, Message,
12+
};
13+
14+
#[cfg(not(feature = "signing"))]
15+
use crate::{read_versioned_msg, write_versioned_msg};
16+
#[cfg(feature = "signing")]
17+
use crate::{SigningConfig, SigningData};
18+
19+
use super::AsyncMavConnection;
20+
21+
pub fn open(settings: &str) -> io::Result<AsyncSerialConnection> {
22+
let settings_toks: Vec<&str> = settings.split(':').collect();
23+
if settings_toks.len() < 2 {
24+
return Err(io::Error::new(
25+
io::ErrorKind::AddrNotAvailable,
26+
"Incomplete port settings",
27+
));
28+
}
29+
30+
let Ok(baud) = settings_toks[1].parse::<u32>() else {
31+
return Err(io::Error::new(
32+
io::ErrorKind::AddrNotAvailable,
33+
"Invalid baud rate",
34+
));
35+
};
36+
37+
let port_name = settings_toks[0];
38+
let mut port = tokio_serial::new(port_name, baud).open_native_async()?;
39+
port.set_data_bits(tokio_serial::DataBits::Eight)?;
40+
port.set_parity(tokio_serial::Parity::None)?;
41+
port.set_stop_bits(tokio_serial::StopBits::One)?;
42+
port.set_flow_control(tokio_serial::FlowControl::None)?;
43+
44+
Ok(AsyncSerialConnection {
45+
port: Mutex::new(AsyncPeekReader::new(port)),
46+
sequence: Mutex::new(0),
47+
protocol_version: MavlinkVersion::V2,
48+
#[cfg(feature = "signing")]
49+
signing_data: None,
50+
})
51+
}
52+
53+
pub struct AsyncSerialConnection {
54+
port: Mutex<AsyncPeekReader<SerialStream>>,
55+
sequence: Mutex<u8>,
56+
protocol_version: MavlinkVersion,
57+
#[cfg(feature = "signing")]
58+
signing_data: Option<SigningData>,
59+
}
60+
61+
#[async_trait::async_trait]
62+
impl<M: Message + Sync + Send> AsyncMavConnection<M> for AsyncSerialConnection {
63+
async fn recv(&self) -> Result<(MavHeader, M), crate::error::MessageReadError> {
64+
let mut port = self.port.lock().await;
65+
66+
#[cfg(not(feature = "signing"))]
67+
let result = read_versioned_msg_async(port.deref_mut(), self.protocol_version).await;
68+
#[cfg(feature = "signing")]
69+
let result = read_versioned_msg_async_signed(
70+
port.deref_mut(),
71+
self.protocol_version,
72+
self.signing_data.as_ref(),
73+
)
74+
.await;
75+
result
76+
}
77+
78+
async fn send(
79+
&self,
80+
header: &MavHeader,
81+
data: &M,
82+
) -> Result<usize, crate::error::MessageWriteError> {
83+
let mut port = self.port.lock().await;
84+
let mut sequence = self.sequence.lock().await;
85+
86+
let header = MavHeader {
87+
sequence: *sequence,
88+
system_id: header.system_id,
89+
component_id: header.component_id,
90+
};
91+
92+
*sequence = sequence.wrapping_add(1);
93+
94+
#[cfg(not(feature = "signing"))]
95+
let result =
96+
write_versioned_msg_async(port.reader_mut(), self.protocol_version, header, data).await;
97+
#[cfg(feature = "signing")]
98+
let result = write_versioned_msg_async_signed(
99+
port.reader_mut(),
100+
self.protocol_version,
101+
header,
102+
data,
103+
self.signing_data.as_ref(),
104+
)
105+
.await;
106+
result
107+
}
108+
109+
fn set_protocol_version(&mut self, version: MavlinkVersion) {
110+
self.protocol_version = version;
111+
}
112+
113+
fn get_protocol_version(&self) -> MavlinkVersion {
114+
self.protocol_version
115+
}
116+
117+
#[cfg(feature = "signing")]
118+
fn setup_signing(&mut self, signing_data: Option<SigningConfig>) {
119+
self.signing_data = signing_data.map(SigningData::from_config)
120+
}
121+
}

mavlink-core/src/async_connection/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ mod tcp;
88
#[cfg(feature = "udp")]
99
mod udp;
1010

11+
#[cfg(feature = "direct-serial")]
12+
mod direct_serial;
13+
1114
mod file;
1215

1316
#[cfg(feature = "signing")]

0 commit comments

Comments
 (0)