use std::ops::Not;
use std::thread;
use crate::actix::*;
use crate::pin::{Error as PinError, Pin};
#[derive(Clone, Copy, Debug)]
pub enum Message {
Perfuse,
Drain,
Stop,
}
impl ActixMessage for Message {
type Result = Result<Option<Direction>>;
}
#[derive(Clone, Copy, Debug)]
pub enum Direction {
Forward,
Backward,
}
impl Not for Direction {
type Output = Self;
fn not(self) -> Self {
match self {
Direction::Forward => Direction::Backward,
Direction::Backward => Direction::Forward,
}
}
}
pub type Result<T> = std::result::Result<T, PinError>;
#[derive(Debug)]
pub struct Pump {
pins: [Pin; 4],
direction: Option<Direction>,
pub invert: bool,
}
impl PartialEq for Pump {
fn eq(&self, other: &Self) -> bool {
self.pins[0].number == other.pins[0].number
&& self.pins[1].number == other.pins[1].number
&& self.pins[2].number == other.pins[2].number
&& self.pins[3].number == other.pins[3].number
}
}
impl Eq for Pump {}
impl Pump {
pub fn try_new(pins: [u16; 4]) -> Result<Self> {
let pins = [
Pin::try_new(pins[0])?,
Pin::try_new(pins[1])?,
Pin::try_new(pins[2])?,
Pin::try_new(pins[3])?,
];
Ok(Self {
direction: None,
pins,
invert: false,
})
}
pub fn new(pins: [u16; 4]) -> Self {
Self::try_new(pins).expect("Pump construction failed.")
}
pub fn set_direction<D>(&mut self, direction: D) -> Result<Option<Direction>>
where
D: Into<Option<Direction>>,
{
let direction = direction.into();
if let Some(direction) = direction {
if !self.is_stopped() {
self.stop()?;
thread::sleep(std::time::Duration::from_millis(20));
}
let direction = if self.invert { !direction } else { direction };
let pins = match direction {
Direction::Forward => (0, 3),
Direction::Backward => (1, 2),
};
let (top, bottom) = (pins.0, pins.1);
self.pins[top].set_high();
self.pins[bottom].set_high();
} else {
for i in 0..4 {
self.pins[i].set_low();
}
}
self.direction = direction;
Ok(direction)
}
pub fn perfuse(&mut self) -> Result<Option<Direction>> {
log::trace!("Setting pump to perfuse");
self.set_direction(Direction::Forward)
}
pub fn drain(&mut self) -> Result<Option<Direction>> {
log::trace!("Setting pump to drain");
self.set_direction(Direction::Backward)
}
pub fn stop(&mut self) -> Result<Option<Direction>> {
log::trace!("Stopping pump");
self.set_direction(None)
}
pub fn is_stopped(&self) -> bool {
self.direction.is_none()
}
}
impl Actor for Pump {
type Context = Context<Self>;
}
impl Handle<Message> for Pump {
type Result = Result<Option<Direction>>;
fn handle(&mut self, message: Message, _context: &mut Self::Context) -> Self::Result {
match message {
Message::Perfuse => self.perfuse(),
Message::Drain => self.drain(),
Message::Stop => self.stop(),
}
}
}