use crate::gpio::{Pin, PinMode, Pins};
use std::any::Any;
use std::collections::VecDeque;
use std::io;
#[derive(Default)]
pub struct NoopPins {}
impl Pins for NoopPins {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn setup(&mut self, _pin: Pin, _mode: PinMode) -> io::Result<()> {
Err(io::Error::other("GPIO backend not compiled in"))
}
fn clear(&mut self, _pin: Pin) -> io::Result<()> {
Err(io::Error::other("GPIO backend not compiled in"))
}
fn clear_all(&mut self) -> io::Result<()> {
Err(io::Error::other("GPIO backend not compiled in"))
}
fn read(&mut self, _pin: Pin) -> io::Result<bool> {
Err(io::Error::other("GPIO backend not compiled in"))
}
fn write(&mut self, _pin: Pin, _v: bool) -> io::Result<()> {
Err(io::Error::other("GPIO backend not compiled in"))
}
}
#[derive(PartialEq)]
enum MockOp {
SetupIn = 1,
SetupInPullDown = 2,
SetupInPullUp = 3,
SetupOut = 4,
Clear = 5,
ClearAll = -1,
ReadLow = 10,
ReadHigh = 11,
WriteLow = 20,
WriteHigh = 21,
}
impl MockOp {
fn encode(pin: Pin, op: Self) -> i32 {
assert!(op != Self::ClearAll);
(pin.0 as i32) * 100 + (op as i32)
}
}
#[derive(Default)]
pub struct MockPins {
reads: VecDeque<(Pin, bool)>,
trace: Vec<i32>,
}
impl MockPins {
pub fn inject_read(&mut self, pin: Pin, high: bool) {
self.reads.push_back((pin, high));
}
pub fn trace(&self) -> &[i32] {
&self.trace
}
}
impl Pins for MockPins {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn setup(&mut self, pin: Pin, mode: PinMode) -> io::Result<()> {
let datum = match mode {
PinMode::In => MockOp::encode(pin, MockOp::SetupIn),
PinMode::InPullDown => MockOp::encode(pin, MockOp::SetupInPullDown),
PinMode::InPullUp => MockOp::encode(pin, MockOp::SetupInPullUp),
PinMode::Out => MockOp::encode(pin, MockOp::SetupOut),
};
self.trace.push(datum);
Ok(())
}
fn clear(&mut self, pin: Pin) -> io::Result<()> {
self.trace.push(MockOp::encode(pin, MockOp::Clear));
Ok(())
}
fn clear_all(&mut self) -> io::Result<()> {
self.trace.push(MockOp::ClearAll as i32);
Ok(())
}
fn read(&mut self, pin: Pin) -> io::Result<bool> {
match self.reads.pop_front() {
Some((read_pin, high)) if read_pin == pin => {
let op = if high { MockOp::ReadHigh } else { MockOp::ReadLow };
self.trace.push(MockOp::encode(pin, op));
Ok(high)
}
Some((read_pin, _)) => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Want to read pin {} but next mock read is for pin {}", pin.0, read_pin.0),
)),
None => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("No mock read available for pin {}", pin.0),
)),
}
}
fn write(&mut self, pin: Pin, v: bool) -> io::Result<()> {
let op = if v { MockOp::WriteHigh } else { MockOp::WriteLow };
self.trace.push(MockOp::encode(pin, op));
Ok(())
}
}