use tokio::io::{AsyncReadExt, AsyncWriteExt}; use serial2_tokio::SerialPort; #[tokio::main(flavor = "current_thread")] async fn main() { if let Err(()) = do_main().await { std::process::exit(1); } } async fn do_main() -> Result<(), ()> { let args: Vec<_> = std::env::args().collect(); if args.len() != 3 { let prog_name = args[0].rsplit_once('/').map(|(_parent, name)| name).unwrap_or(&args[0]); eprintln!("Usage: {} PORT BAUD", prog_name); return Err(()); } let port_name = &args[1]; let baud_rate: u32 = args[2] .parse() .map_err(|_| eprintln!("Error: invalid baud rate: {}", args[2]))?; let port = SerialPort::open(port_name, baud_rate) .map_err(|e| eprintln!("Error: Failed to open {}: {}", port_name, e))?; tokio::try_join!( read_stdin_loop(&port, port_name), read_serial_loop(&port, port_name), )?; Ok(()) } async fn read_stdin_loop(port: &SerialPort, port_name: &str) -> Result<(), ()> { let mut stdin = tokio::io::stdin(); let mut buffer = [0; 512]; loop { let read = stdin .read(&mut buffer) .await .map_err(|e| eprintln!("Error: Failed to read from stdin: {}", e))?; if read == 0 { return Ok(()); } else { port.write(&buffer[..read]) .await .map_err(|e| eprintln!("Error: Failed to write to {}: {}", port_name, e))?; } } } async fn read_serial_loop(port: &SerialPort, port_name: &str) -> Result<(), ()> { let mut stdout = tokio::io::stdout(); let mut buffer = [0; 512]; loop { match port.read(&mut buffer).await { Ok(0) => return Ok(()), Ok(n) => { stdout .write_all(&buffer[..n]) .await .map_err(|e| eprintln!("Error: Failed to write to stdout: {}", e))?; }, Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => continue, Err(e) => { eprintln!("Error: Failed to read from {}: {}", port_name, e); return Err(()); }, } } }