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}