serialport-stream 0.3.0

Async Stream and AsyncRead/AsyncWrite for serial ports using platform-specific I/O
Documentation

serialport-stream-rs

Async serial port I/O as futures::Stream, AsyncRead, and AsyncWrite. Uses POSIX termios on Unix and Win32 COMM APIs on Windows.

Installation

[dependencies]
serialport-stream = "0.3"

Examples below also use futures-lite (blocking) or tokio.

Usage

Stream (blocking)

use serialport_stream::new;
use futures_lite::stream;

fn main() -> std::io::Result<()> {
    let stream = new("COM3", 115200).dtr_on_open(true).open()?;

    for chunk in stream::block_on(stream) {
        println!("{:?}", chunk?);
    }

    Ok(())
}

Stream (Tokio)

use serialport_stream::{new, TryStreamExt};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut stream = new("/dev/ttyUSB0", 9600).open()?;

    while let Some(bytes) = stream.try_next().await? {
        println!("Received: {bytes:?}");
    }

    Ok(())
}

Reading

A background thread fills one in-memory FIFO. There is no backpressure; the buffer can grow without bound.

API Each call returns
Stream / try_next All bytes in the FIFO (buffer drained)
AsyncRead Up to your buffer length; remainder stays in the FIFO

Use one read style per port. Mixing Stream and AsyncRead can split messages across calls.

AsyncReadExt is re-exported (read, read_to_end, etc.). Example: cargo run --example tokio_async_read -- /dev/ttyUSB0 115200.

For tokio::io::AsyncRead, bridge with tokio_util::compat (tokio-util feature compat).

Writing

AsyncWrite / AsyncWriteExt are re-exported. The first write starts a background thread.

use serialport_stream::{new, AsyncWriteExt, TryStreamExt};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut stream = new("/dev/ttyUSB0", 115200).open()?;

    stream.write_all(b"PING\r\n").await?;
    stream.flush().await?;

    if let Some(reply) = stream.try_next().await? {
        println!("Received: {reply:?}");
    }

    Ok(())
}

Example: cargo run --example tokio_async_rw -- /dev/ttyUSB0 115200.

For tokio::io::AsyncWrite, use tokio_util::compat as above.

Builder

Open with new(path, baud_rate), then chain options and call .open():

  • .data_bits, .parity, .stop_bits, .flow_control — default is 8N1, no flow control
  • .dtr_on_open(bool) — drive DTR on open: true asserts, false clears (default: false)
  • .clear(ClearBuffer::Input | Output | All) — purge driver buffers at open

Types DataBits, Parity, StopBits, FlowControl, and ClearBuffer are exported from serialport_stream.

Acknowledgements

Some of the platform I/O code is inspired by serialport-rs.

License

This project is licensed under either of:

at your option.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.