1use std::future::Future;
39use std::pin::Pin;
40use std::sync::{Arc, Mutex};
41use std::task::{Context, Poll};
42
43macro_rules! trace_info {
44 ($($tt:tt)*) => {
45 #[cfg(feature = "tracing")]
46 tracing::info!($($tt)*);
47 };
48}
49
50mod platform;
51mod types;
52
53pub mod line_settings;
54pub use types::{ClearBuffer, DataBits, FlowControl, Parity, StopBits};
55
56use crate::platform::PlatformStream;
57use futures::task::AtomicWaker;
58
59fn clone_io_error(err: &std::io::Error) -> std::io::Error {
60 match err.raw_os_error() {
61 Some(code) => std::io::Error::from_raw_os_error(code),
62 None => std::io::Error::new(err.kind(), err.to_string()),
63 }
64}
65
66pub use futures::io::{AsyncRead, AsyncReadExt};
67pub use futures::io::{AsyncWrite, AsyncWriteExt};
68pub use futures::stream::{Stream, TryStreamExt};
69
70#[derive(Debug)]
71pub(crate) struct EventsInnerRead {
72 pub(crate) in_buffer: Mutex<Vec<u8>>,
73 pub(crate) stream_error: Mutex<Option<std::io::Error>>,
74 pub(crate) waker: AtomicWaker,
75}
76
77impl EventsInnerRead {
78 pub(crate) fn new() -> Self {
79 Self {
80 in_buffer: Mutex::new(Vec::new()),
81 stream_error: Mutex::new(None),
82 waker: AtomicWaker::new(),
83 }
84 }
85}
86
87#[derive(Debug)]
88pub(crate) struct EventsInnerWrite {
89 pub(crate) write_error: Mutex<Option<std::io::Error>>,
90 pub(crate) waker: AtomicWaker,
91}
92
93impl EventsInnerWrite {
94 pub(crate) fn new() -> Self {
95 Self {
96 write_error: Mutex::new(None),
97 waker: AtomicWaker::new(),
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct SerialPortStreamBuilder {
127 pub(crate) path: String,
128 pub(crate) baud_rate: u32,
129 pub(crate) data_bits: DataBits,
130 pub(crate) flow_control: FlowControl,
131 pub(crate) parity: Parity,
132 pub(crate) stop_bits: StopBits,
133 pub(crate) dtr_on_open: bool,
134 pub(crate) clear_buffer: Option<ClearBuffer>,
135}
136
137impl SerialPortStreamBuilder {
138 #[allow(clippy::assigning_clones)]
144 #[must_use]
145 pub fn path<'a>(mut self, path: impl Into<std::borrow::Cow<'a, str>>) -> Self {
146 self.path = path.into().as_ref().to_owned();
147 self
148 }
149
150 #[must_use]
154 pub fn baud_rate(mut self, baud_rate: u32) -> Self {
155 self.baud_rate = baud_rate;
156 self
157 }
158
159 #[must_use]
163 pub fn data_bits(mut self, data_bits: DataBits) -> Self {
164 self.data_bits = data_bits;
165 self
166 }
167
168 #[must_use]
172 pub fn flow_control(mut self, flow_control: FlowControl) -> Self {
173 self.flow_control = flow_control;
174 self
175 }
176
177 #[must_use]
181 pub fn parity(mut self, parity: Parity) -> Self {
182 self.parity = parity;
183 self
184 }
185
186 #[must_use]
190 pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
191 self.stop_bits = stop_bits;
192 self
193 }
194
195 #[must_use]
199 pub fn dtr_on_open(mut self, state: bool) -> Self {
200 self.dtr_on_open = state;
201 self
202 }
203
204 #[must_use]
208 pub fn clear(mut self, buffer: ClearBuffer) -> Self {
209 self.clear_buffer = Some(buffer);
210 self
211 }
212
213 pub fn open(self) -> std::io::Result<SerialPortStream> {
218 let read_inner = Arc::new(EventsInnerRead::new());
219 let write_inner = Arc::new(EventsInnerWrite::new());
220 Ok(SerialPortStream {
221 platform: PlatformStream::new(self, read_inner.clone(), write_inner.clone())?,
222 read_inner,
223 write_inner,
224 flush_task: None,
225 write_in_flight: false,
226 })
227 }
228}
229
230pub fn new<'a>(
254 path: impl Into<std::borrow::Cow<'a, str>>,
255 baud_rate: u32,
256) -> SerialPortStreamBuilder {
257 SerialPortStreamBuilder {
258 path: path.into().into_owned(),
259 baud_rate,
260 data_bits: DataBits::Eight,
261 flow_control: FlowControl::None,
262 parity: Parity::None,
263 stop_bits: StopBits::One,
264 dtr_on_open: false,
265 clear_buffer: None,
266 }
267}
268
269pub struct SerialPortStream {
291 platform: PlatformStream,
292 read_inner: Arc<EventsInnerRead>,
293 write_inner: Arc<EventsInnerWrite>,
294 flush_task: Option<blocking::Task<std::io::Result<()>>>,
295 write_in_flight: bool,
296}
297
298impl std::fmt::Debug for SerialPortStream {
299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 f.debug_struct("SerialPortStream")
301 .field("platform", &self.platform)
302 .field("read_inner", &self.read_inner)
303 .field("write_inner", &self.write_inner)
304 .field("flush_task", &self.flush_task.as_ref().map(|_| "..."))
305 .field("write_in_flight", &self.write_in_flight)
306 .finish()
307 }
308}
309
310impl SerialPortStream {
311 fn poll_receiver_ready(&mut self, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
312 self.read_inner.waker.register(cx.waker());
313
314 if let Some(err) = self.read_inner.stream_error.lock().unwrap().as_ref() {
315 return Poll::Ready(Err(clone_io_error(err)));
316 }
317
318 if !self.platform.is_read_thread_started() {
319 self.platform.start_read_thread();
320 return Poll::Pending;
321 }
322
323 Poll::Ready(Ok(()))
324 }
325
326 fn poll_writer_ready(&mut self, cx: &mut Context<'_>) -> std::io::Result<()> {
327 self.write_inner.waker.register(cx.waker());
328
329 if let Some(err) = self.write_inner.write_error.lock().unwrap().as_ref() {
330 return Err(clone_io_error(err));
331 }
332
333 if !self.platform.is_write_thread_started() {
334 self.platform.start_write_thread();
335 }
336
337 Ok(())
338 }
339
340 pub fn try_poll_next(
345 &mut self,
346 cx: &mut Context<'_>,
347 ) -> Poll<Option<Result<Vec<u8>, std::io::Error>>> {
348 match self.poll_receiver_ready(cx) {
349 Poll::Pending => Poll::Pending,
350 Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))),
351 Poll::Ready(Ok(())) => {
352 let mut buffer = self.read_inner.in_buffer.lock().unwrap();
353 if !buffer.is_empty() {
354 let data = buffer.drain(..).collect();
356 return Poll::Ready(Some(Ok(data)));
357 }
358
359 Poll::Pending
360 }
361 }
362 }
363
364 pub fn set_baudrate(&mut self, baud_rate: u32) -> std::io::Result<()> {
368 self.platform.set_baud_rate(baud_rate)
369 }
370}
371
372unsafe impl Send for SerialPortStream {}
373
374unsafe impl Sync for SerialPortStream {}
375
376impl AsyncRead for SerialPortStream {
377 fn poll_read(
378 mut self: Pin<&mut Self>,
379 cx: &mut Context<'_>,
380 buf: &mut [u8],
381 ) -> Poll<std::io::Result<usize>> {
382 assert!(!buf.is_empty());
383 let this = self.as_mut().get_mut();
384 match this.poll_receiver_ready(cx) {
385 Poll::Pending => Poll::Pending,
386 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
387 Poll::Ready(Ok(())) => {
388 let mut buffer = this.read_inner.in_buffer.lock().unwrap();
389 if buffer.is_empty() {
390 return Poll::Pending;
391 }
392 let n = buf.len().min(buffer.len());
393 buf[..n].copy_from_slice(&buffer[..n]);
394 buffer.drain(..n);
395 let cached_bytes = buffer.len();
396 if cached_bytes > 0 {
397 trace_info!(
398 read_bytes = n,
399 cached_bytes,
400 "serialport-stream receive buffer after AsyncRead read"
401 );
402 }
403 Poll::Ready(Ok(n))
404 }
405 }
406 }
407}
408
409impl Stream for SerialPortStream {
410 type Item = Result<Vec<u8>, std::io::Error>;
411
412 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
413 self.try_poll_next(cx)
414 }
415}
416
417impl AsyncWrite for SerialPortStream {
418 fn poll_write(
419 mut self: Pin<&mut Self>,
420 cx: &mut Context<'_>,
421 buf: &[u8],
422 ) -> Poll<std::io::Result<usize>> {
423 assert!(!buf.is_empty());
424 let this = self.as_mut().get_mut();
425 let result = match this.poll_writer_ready(cx) {
426 Err(e) => Poll::Ready(Err(e)),
427 Ok(()) => this.platform.poll_write(buf),
428 };
429 this.write_in_flight = result.is_pending();
431 result
432 }
433
434 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
435 let this = self.as_mut().get_mut();
436
437 this.write_inner.waker.register(cx.waker());
438
439 if let Some(err) = this.write_inner.write_error.lock().unwrap().as_ref() {
440 return Poll::Ready(Err(clone_io_error(err)));
441 }
442
443 if this.write_in_flight {
444 return Poll::Pending;
445 }
446
447 if this.flush_task.is_none() {
448 this.flush_task = Some(this.platform.flush_tx_unblocked());
449 }
450
451 let task = this.flush_task.as_mut().expect("flush task");
452 match Pin::new(task).poll(cx) {
453 Poll::Ready(result) => {
454 this.flush_task = None;
455 Poll::Ready(result)
456 }
457 Poll::Pending => Poll::Pending,
458 }
459 }
460
461 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
462 self.poll_flush(cx)
463 }
464}