extern crate kawaii; use std::time::Duration; use std::thread; use std::thread::JoinHandle; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use self::kawaii::gpio::{AsyncPort, Edge, Value}; #[cfg(feature = "measure")] use self::kawaii::Measure; #[derive(Debug)] pub struct EmergencyStop { thread: Option>, pub state: Arc, } impl EmergencyStop { pub fn new(stop_port: u8) -> std::io::Result { let name = format!("EmergencyStop(port = {})", stop_port); let state = Arc::new(AtomicBool::new(false)); let mut port = AsyncPort::new(stop_port, Edge::Both)?; let state_clone = state.clone(); let thread = thread::Builder::new() .name(name) .spawn(move || EmergencyStop::thread(&mut port, state_clone))?; Ok(EmergencyStop { thread: Some(thread), state: state, }) } fn thread(port: &mut AsyncPort, state: Arc) { #[cfg(feature = "measure")] let mut measure = Measure::new(format!("EmergencyStop(port = {})", port.port.number)); // clear first value port.poll(Some(Duration::new(0, 0))).is_ok(); while !state.load(Ordering::Relaxed) { #[cfg(feature = "measure")] measure.start(); let timeout = Some(Duration::new(1, 0)); #[cfg(not(feature = "measure"))] let value = port.poll(timeout); #[cfg(feature = "measure")] let value = port.poll_measure(timeout, &mut measure); // continue on timeout match value { Ok(value) => { if let Some(value) = value { match value { Value::High => { #[cfg(debug_assertions)] println!("EmergencyStop! ({:?})", value); state.store(true, Ordering::Relaxed); } _ => { #[cfg(debug_assertions)] println!("EmergencyStop ignored: ({:?})", value); } } } } Err(e) => { #[cfg(debug_assertions)] println!("EmergencyStop! ({:?})", e); state.store(true, Ordering::Relaxed); } } #[cfg(feature = "measure")] measure.stop(); } } } impl Drop for EmergencyStop { fn drop(&mut self) { self.state.store(true, Ordering::Relaxed); if let Some(thread) = self.thread.take() { thread.join().is_ok(); } } }