#serial-port #serial #usb #tty #driver #deadlock

serial-arbiter

Serial Port Arbiter - Manages serial port access and ensures it recovers from failures

1 unstable release

new 0.1.0 Mar 20, 2025

#1055 in Hardware support

MIT license

16KB
262 lines

Serial Port Arbiter

This is a wrapper for serialport lib which adds the following features:

  1. Prevents deadlocks caused by input buffer starvation
  2. Prevents data garbling by implementing transaction queueing
  3. Handles gracefully interrupts and timeout errors
  4. Handles gracefully connection errors and automatically reconnects
  5. Provides a more convenient API than the raw io::Read and io::Write

This is an "async-less" library.

There are two plain old background threads. They are running in parallel. One is responsible for sending the data to the serial port and the other one is responsible for the reception of the incomming data from the serial port. This design ensures that there will be no buffer underruns even when sending very big messages to the serial port. I.e deadlocks are solved because the serial port is always ready to accept more data from the slave device.

Example

use std::io;
use serialport::*;
use serial_arbiter::*;
use std::time::*;

fn main() -> io::Result<()> {
    let cfg = serialport::new("/dev/ttyACM0", 115200)
        .data_bits(DataBits::Eight)
        .parity(Parity::None)
        .stop_bits(StopBits::One)
        .flow_control(FlowControl::None)
        .timeout(Duration::from_millis(0));

    let port = Arbiter::new(cfg);

    let request = format!("{}\n", r#"{"jsonrpc":"2.0","id":777,"method":"hello_world","params":"Hello World!"}"#);
    let deadline = Instant::now() + Duration::from_millis(10);
    print!("\nSending request:\n{request}");
    port.write_str(request, deadline)?;

    let deadline = Instant::now() + Duration::from_millis(10);
    println!("\nWaiting for response...");
    let response = port.read_string(deadline)?.unwrap_or("<EMPTY>".to_string());
    println!("Response: {response}\n");

    Ok(())
}

You should be seeing something like this:

Sending request:
{"jsonrpc":"2.0","id":777,"method":"hello_world","params":"Hello World!"}

Waiting for response...
Response: {"jsonrpc":"2.0","error":{"code":32935,"message":"Unknown method"},"id":777}

Dependencies

~3MB
~52K SLoC