use core::marker::PhantomData;
use expander::pin::{ExpanderIO, PortPin};
use expander::Expander;
use interface::ExpanderInterface;
use mutex::IOMutex;
use registers::valid_port;
pub struct ImmediateIO<M, EI>(M, PhantomData<EI>)
where
M: IOMutex<Expander<EI>>,
EI: ExpanderInterface + Send;
impl<M, EI> ImmediateIO<M, EI>
where
M: IOMutex<Expander<EI>>,
EI: ExpanderInterface + Send,
{
pub(crate) fn new(expander: Expander<EI>) -> Self {
ImmediateIO(M::new(expander), PhantomData)
}
pub fn port_pin<'io>(&'io self, port: u8) -> PortPin<'io, Self> {
PortPin::new(self, valid_port(port))
}
}
impl<M, EI> ExpanderIO for ImmediateIO<M, EI>
where
M: IOMutex<Expander<EI>>,
EI: ExpanderInterface + Send,
{
type Error = EI::Error;
fn write_port(&self, port: u8, bit: bool) -> Result<(), EI::Error> {
self.0.lock(|ex| ex.write_port(port, bit))
}
fn read_port(&self, port: u8) -> Result<bool, EI::Error> {
self.0.lock(|ex| ex.read_port(port))
}
}
#[cfg(test)]
mod tests {
use expander::Expander;
use hal::digital::v2::{InputPin, OutputPin};
use interface::test_spy::{TestRegister as TR, TestSpyInterface};
use mutex::DefaultMutex;
#[test]
fn single_pin_write() {
let ei = TestSpyInterface::new();
let io = Expander::new(ei.split()).into_immediate::<DefaultMutex<_>>();
let mut pin_twelve = io.port_pin(12);
assert!(pin_twelve.set_high().is_ok());
assert_eq!(ei.get(0x2C), TR::WrittenValue(0x01));
}
#[test]
fn single_pin_read() {
let mut ei = TestSpyInterface::new();
let io = Expander::new(ei.split()).into_immediate::<DefaultMutex<_>>();
let pin_twelve = io.port_pin(12);
ei.set(0x2C, TR::ResetValue(0x00));
assert_eq!(pin_twelve.is_high(), Ok(false));
ei.set(0x2C, TR::ResetValue(0x01));
assert_eq!(pin_twelve.is_high(), Ok(true));
}
#[test]
fn multi_pin_read_write() {
let mut ei = TestSpyInterface::new();
let io = Expander::new(ei.split()).into_immediate::<DefaultMutex<_>>();
let mut pin_twelve = io.port_pin(12);
let mut pin_sixteen = io.port_pin(16);
let pin_twenty = io.port_pin(20);
ei.set(0x34, TR::ResetValue(0x01));
assert!(pin_twelve.set_high().is_ok());
assert!(pin_sixteen.set_low().is_ok());
assert_eq!(pin_twenty.is_low(), Ok(false));
assert_eq!(ei.get(0x2C), TR::WrittenValue(0x01));
assert_eq!(ei.get(0x30), TR::WrittenValue(0x00));
}
}