use std::io::{Error, ErrorKind, Read, Write};
use std::thread;
use std::time::Duration;
use mio::event::Source;
use mio::{Events, Interest, Poll, Token, Waker};
use mio_serial::SerialPortBuilderExt;
use thread_guard::ThreadGuard;
const PORT_PATH_A: &str = "/tmp/ttyS20";
const PORT_PATH_B: &str = "/tmp/ttyS21";
const SERIAL: Token = Token(0);
const WAKE: Token = Token(1);
fn port_a() -> Result<ThreadGuard<Result<(), Error>>, Error> {
let mut poll = Poll::new()?;
let mut port = mio_serial::new(PORT_PATH_A, 0).open_native_async()?;
let registry = poll.registry();
port.register(registry, SERIAL, Interest::READABLE)?;
let waker = Waker::new(registry, WAKE)?;
let guard = ThreadGuard::with_actions(
thread::spawn(move || {
let mut events = Events::with_capacity(256);
let mut buf = vec![0; 256];
'poll: loop {
poll.poll(&mut events, None).unwrap();
for event in events.iter() {
let token = event.token();
if token == WAKE {
break 'poll;
} else {
loop {
match port.read(&mut buf) {
Ok(len) => {
println!(
"Port A received a message: {:?}, going to echo it.",
&buf[..len]
);
if port.write(&buf[..len])? != len {
return Err(Error::new(
ErrorKind::Other,
"Write did not fully succeed.",
));
};
}
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
break;
}
Err(e) => return Err(e),
}
}
}
}
}
Ok(())
}),
move |_| {
let _ = waker.wake();
waker
},
|_waker, r| {
println!("Port A thread exited with the result {:?}.", r);
},
);
Ok(guard)
}
fn scenario_echo_join() -> Result<(), Error> {
let port_a = port_a()?;
let mut port_b = serialport::new(PORT_PATH_B, 0).open()?;
let message = vec![1, 2, 3, 4];
assert_eq!(port_b.write(&message)?, message.len());
let mut buf = vec![0, 0, 0, 0];
port_b.set_timeout(Duration::from_secs(5))?;
let rec_len = port_b.read(&mut buf)?;
assert_eq!(rec_len, message.len());
println!("Port B received a message {:?}.", &buf[..rec_len]);
assert_eq!(message, buf);
match port_a.join() {
Ok(r) => r?,
Err(e) => panic!("Port A panic {:?}.", e),
}
Ok(())
}
fn scenario_drop() -> Result<(), Error> {
let _port_a = port_a()?;
Ok(())
}
fn main() -> Result<(), Error> {
scenario_echo_join()?;
scenario_drop()?;
Ok(())
}