cat_dev/serial/async_sys/mod.rs
1//! The OS specifical asynchronous serial port implementation.
2//!
3//! This module provides [`RawAsyncSerialPort`], a very thin wrapper around
4//! the serial port provided by the underlying implementation using tokio's
5//! an asynchronous file descriptor on unix, or on windows wrapping in a
6//! named pipe client so we interact with the port asynchronously safely.
7
8#[cfg(any(
9 target_os = "linux",
10 target_os = "freebsd",
11 target_os = "openbsd",
12 target_os = "netbsd",
13 target_os = "macos"
14))]
15mod unix;
16#[cfg(target_os = "windows")]
17mod windows;
18
19use tokio::io::{AsyncRead, AsyncWrite};
20#[cfg(any(
21 target_os = "linux",
22 target_os = "freebsd",
23 target_os = "openbsd",
24 target_os = "netbsd",
25 target_os = "macos"
26))]
27use unix::RawAsyncSerialPort;
28#[cfg(target_os = "windows")]
29use windows::RawAsyncSerialPort;
30
31use crate::serial::SyncSerialPort;
32use std::{
33 io::{IoSlice, IoSliceMut, Result as IoResult},
34 path::{Path, PathBuf},
35 pin::Pin,
36 task::{Context, Poll},
37};
38use tokio::io::ReadBuf;
39
40/// An asynchronous serial port.
41pub struct AsyncSerialPort {
42 inner: RawAsyncSerialPort,
43}
44
45impl AsyncSerialPort {
46 /// Get a list of available serial ports.
47 ///
48 /// ## Errors
49 ///
50 /// If your platform is unsupported, or an OS error occurs.
51 pub fn available_ports() -> IoResult<Vec<PathBuf>> {
52 SyncSerialPort::available_ports()
53 }
54
55 /// Open and configure a serial port by path or name.
56 ///
57 /// On Unix systems, the `name` parameter must be a path to a TTY device. On
58 /// Windows, it must be the name of a COM device, such as COM1, COM2, etc.
59 ///
60 /// The library automatically uses the win32 device namespace on Windows, so
61 /// COM ports above COM9 are supported out of the box.
62 ///
63 /// ## Errors
64 ///
65 /// If we cannot open, or configure the serial device at path.
66 pub fn new(path: impl AsRef<Path>) -> IoResult<Self> {
67 Ok(Self {
68 inner: RawAsyncSerialPort::new(SyncSerialPort::new(path)?)?,
69 })
70 }
71
72 /// Try to clone the serial port handle.
73 ///
74 /// The cloned object refers to the same serial port.
75 ///
76 /// Mixing reads and writes on different handles to the same serial port
77 /// from different threads may lead to unexpect results. The data may end
78 /// up interleaved in unpredictable ways.
79 ///
80 /// ## Errors
81 ///
82 /// If we cannot clone the underlying file descriptor.
83 pub fn try_clone(&self) -> IoResult<Self> {
84 let inner = self.inner.try_clone()?;
85 Ok(Self { inner })
86 }
87
88 /// Read bytes from the serial port.
89 ///
90 /// This is identical to
91 /// [`AsyncReadExt::read()`][tokio::io::AsyncReadExt::read], except that
92 /// this function takes a const reference `&self`. This allows you to use
93 /// the serial port concurrently from multiple tasks.
94 ///
95 /// Note that there are no guarantees about which task receives what data
96 /// when multiple tasks are reading from the serial port. You should normally
97 /// limit yourself to a single reading task and a single writing task.
98 ///
99 /// ## Errors
100 ///
101 /// If the underlying OS, or device throws an error.
102 pub async fn read(&self, buff: &mut [u8]) -> IoResult<usize> {
103 self.inner.read(buff).await
104 }
105
106 /// If this implementation supports vectored reads.
107 #[must_use]
108 pub const fn can_read_vectored() -> bool {
109 RawAsyncSerialPort::can_read_vectored()
110 }
111
112 /// Read bytes from the serial port into a slice of buffers.
113 ///
114 /// Note that there are no guarantees about which task receives what data
115 /// when multiple tasks are reading from the serial port. You should
116 /// normally limit yourself to a single reading task and a single writing
117 /// task.
118 ///
119 /// ## Errors
120 ///
121 /// If the underlying OS, or device throws an error.
122 pub async fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> IoResult<usize> {
123 self.inner.read_vectored(bufs).await
124 }
125
126 /// Write bytes to the serial port.
127 ///
128 /// This is identical to
129 /// [`AsyncWriteExt::write()`][tokio::io::AsyncWriteExt::write], except that
130 /// this function takes a const reference `&self`. This allows you to use the
131 /// serial port concurrently from multiple tasks.
132 ///
133 /// Note that data written to the same serial port from multiple tasks may
134 /// end up interleaved at the receiving side. You should normally limit
135 /// yourself to a single reading task and a single writing task.
136 ///
137 /// ## Errors
138 ///
139 /// If the underlying OS, or device throws an error.
140 pub async fn write(&self, buff: &[u8]) -> IoResult<usize> {
141 self.inner.write(buff).await
142 }
143
144 /// Write all bytes to the serial port.
145 ///
146 /// This will continue to call [`Self::write()`] until the entire buffer
147 /// has been written, or an I/O error occurs.
148 ///
149 /// This is identical to
150 /// [`AsyncWriteExt::write_all()`][tokio::io::AsyncWriteExt::write_all],
151 /// except that this function takes a const reference `&self`. This allows
152 /// you to use the serial port concurrently from multiple tasks.
153 ///
154 /// Note that data written to the same serial port from multiple tasks may
155 /// end up interleaved at the receiving side. You should normally limit
156 /// yourself to a single reading task and a single writing task.
157 ///
158 /// ## Errors
159 ///
160 /// If the underlying OS, or device throws an error.
161 pub async fn write_all(&self, buff: &[u8]) -> IoResult<()> {
162 let mut written = 0;
163 while written < buff.len() {
164 written += self.write(&buff[written..]).await?;
165 }
166 Ok(())
167 }
168
169 /// If this implementation supports vectored writes.
170 #[must_use]
171 pub const fn can_write_vectored() -> bool {
172 RawAsyncSerialPort::can_write_vectored()
173 }
174
175 /// Write bytes to the serial port from a slice of buffers.
176 ///
177 /// This is identical to
178 /// [`AsyncWriteExt::write_vectored()`][tokio::io::AsyncWriteExt::write_vectored],
179 /// except that this function takes a const reference `&self`. This allows
180 /// you to use the serial port concurrently from multiple tasks.
181 ///
182 /// Note that data written to the same serial port from multiple tasks may
183 /// end up interleaved at the receiving side. You should normally limit
184 /// yourself to a single reading task and a single writing task.
185 ///
186 /// ## Errors
187 ///
188 /// If the underlying OS, or device throws an error.
189 pub async fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> IoResult<usize> {
190 self.inner.write_vectored(bufs).await
191 }
192
193 /// Discard the kernel input and output buffers for the serial port.
194 ///
195 /// When you write to a serial port, the data may be put in a buffer by the
196 /// OS to be transmitted by the actual device later. Similarly, data received
197 /// on the device can be put in a buffer by the OS untill you read it. This
198 /// function clears both buffers: any untransmitted data and received but
199 /// unread data is discarded by the OS.
200 ///
201 /// ## Errors
202 ///
203 /// If the underlying OS, or device throws an error.
204 pub fn discard_buffers(&self) -> IoResult<()> {
205 self.inner.with_raw(SyncSerialPort::discard_buffers)
206 }
207
208 /// Discard the kernel input buffers for the serial port.
209 ///
210 /// Data received on the device can be put in a buffer by the OS untill
211 /// you read it. This function clears that buffer: received but unread
212 /// data is discarded by the OS.
213 ///
214 /// This is particularly useful when communicating with a device that only
215 /// responds to commands that you send to it. If you discard the input
216 /// buffer before sending the command, you discard any noise that may have
217 /// been received after the last command.
218 ///
219 /// ## Errors
220 ///
221 /// If the underlying OS, or device throws an error.
222 pub fn discard_input_buffer(&self) -> IoResult<()> {
223 self.inner.with_raw(SyncSerialPort::discard_input_buffer)
224 }
225
226 /// Discard the kernel output buffers for the serial port.
227 ///
228 /// When you write to a serial port, the data is generally put in a buffer
229 /// by the OS to be transmitted by the actual device later. This function
230 /// clears that buffer: any untransmitted data is discarded by the OS.
231 ///
232 /// ## Errors
233 ///
234 /// If the underlying OS, or device throws an error.
235 pub fn discard_output_buffer(&self) -> IoResult<()> {
236 self.inner.with_raw(SyncSerialPort::discard_output_buffer)
237 }
238
239 /// Set the state of the Ready To Send line.
240 ///
241 /// If hardware flow control is enabled on the serial port, it is platform
242 /// specific what will happen. The function may fail with an error or it
243 /// may silently be ignored. It may even succeed and interfere with the
244 /// flow control.
245 ///
246 /// ## Errors
247 ///
248 /// If the underlying OS, or device throws an error.
249 pub fn set_rts(&self, state: bool) -> IoResult<()> {
250 self.inner.with_raw(|raw| raw.set_rts(state))
251 }
252
253 /// Read the state of the Clear To Send line.
254 ///
255 /// If hardware flow control is enabled on the serial port, it is platform
256 /// specific what will happen. The function may fail with an error, it
257 /// may return a bogus value, or it may return the actual state of the CTS
258 /// line.
259 ///
260 /// ## Errors
261 ///
262 /// If the underlying OS, or device throws an error.
263 pub fn read_cts(&self) -> IoResult<bool> {
264 self.inner.with_raw(SyncSerialPort::read_cts)
265 }
266
267 /// Set the state of the Data Terminal Ready line.
268 ///
269 /// If hardware flow control is enabled on the serial port, it is platform
270 /// specific what will happen. The function may fail with an error or it
271 /// may silently be ignored.
272 ///
273 /// ## Errors
274 ///
275 /// If the underlying OS, or device throws an error.
276 pub fn set_dtr(&self, state: bool) -> IoResult<()> {
277 self.inner.with_raw(|raw| raw.set_dtr(state))
278 }
279
280 /// Read the state of the Data Set Ready line.
281 ///
282 /// If hardware flow control is enabled on the serial port, it is platform
283 /// specific what will happen. The function may fail with an error, it may
284 /// return a bogus value, or it may return the actual state of the DSR line.
285 ///
286 /// ## Errors
287 ///
288 /// If the underlying OS, or device throws an error.
289 pub fn read_dsr(&self) -> IoResult<bool> {
290 self.inner.with_raw(SyncSerialPort::read_dsr)
291 }
292
293 /// Read the state of the Ring Indicator line.
294 ///
295 /// This line is also sometimes also called the RNG or RING line.
296 ///
297 /// ## Errors
298 ///
299 /// If the underlying OS, or device throws an error.
300 pub fn read_ri(&self) -> IoResult<bool> {
301 self.inner.with_raw(SyncSerialPort::read_ri)
302 }
303
304 /// Read the state of the Carrier Detect (CD) line.
305 ///
306 /// This line is also called the Data Carrier Detect (DCD) line
307 /// or the Receive Line Signal Detect (RLSD) line.
308 ///
309 /// ## Errors
310 ///
311 /// If the underlying OS, or device throws an error.
312 pub fn read_cd(&self) -> IoResult<bool> {
313 self.inner.with_raw(SyncSerialPort::read_cd)
314 }
315}
316
317impl AsyncRead for AsyncSerialPort {
318 fn poll_read(
319 self: Pin<&mut Self>,
320 ctx: &mut Context<'_>,
321 buff: &mut ReadBuf<'_>,
322 ) -> Poll<IoResult<()>> {
323 self.get_mut().inner.poll_read(ctx, buff)
324 }
325}
326
327impl AsyncWrite for AsyncSerialPort {
328 fn poll_write(
329 self: Pin<&mut Self>,
330 ctx: &mut Context<'_>,
331 buff: &[u8],
332 ) -> Poll<IoResult<usize>> {
333 self.get_mut().inner.poll_write(ctx, buff)
334 }
335
336 fn poll_write_vectored(
337 self: Pin<&mut Self>,
338 ctx: &mut Context<'_>,
339 bufs: &[IoSlice<'_>],
340 ) -> Poll<IoResult<usize>> {
341 self.get_mut().inner.poll_write_vectored(ctx, bufs)
342 }
343
344 fn poll_flush(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<IoResult<()>> {
345 // We can't do `tcdrain()` asynchronously :(
346 Poll::Ready(Ok(()))
347 }
348
349 fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<IoResult<()>> {
350 self.get_mut().inner.poll_shutdown(ctx)
351 }
352}