endbasic_std/gpio/
fakes.rs1use crate::gpio::{Pin, PinMode, Pins};
19use std::any::Any;
20use std::collections::VecDeque;
21use std::io;
22
23#[derive(Default)]
25pub struct NoopPins {}
26
27impl Pins for NoopPins {
28 fn as_any(&self) -> &dyn Any {
29 self
30 }
31
32 fn as_any_mut(&mut self) -> &mut dyn Any {
33 self
34 }
35
36 fn setup(&mut self, _pin: Pin, _mode: PinMode) -> io::Result<()> {
37 Err(io::Error::other("GPIO backend not compiled in"))
38 }
39
40 fn clear(&mut self, _pin: Pin) -> io::Result<()> {
41 Err(io::Error::other("GPIO backend not compiled in"))
42 }
43
44 fn clear_all(&mut self) -> io::Result<()> {
45 Err(io::Error::other("GPIO backend not compiled in"))
46 }
47
48 fn read(&mut self, _pin: Pin) -> io::Result<bool> {
49 Err(io::Error::other("GPIO backend not compiled in"))
50 }
51
52 fn write(&mut self, _pin: Pin, _v: bool) -> io::Result<()> {
53 Err(io::Error::other("GPIO backend not compiled in"))
54 }
55}
56
57#[derive(PartialEq)]
59enum MockOp {
60 SetupIn = 1,
61 SetupInPullDown = 2,
62 SetupInPullUp = 3,
63 SetupOut = 4,
64
65 Clear = 5,
66 ClearAll = -1,
67
68 ReadLow = 10,
69 ReadHigh = 11,
70
71 WriteLow = 20,
72 WriteHigh = 21,
73}
74
75impl MockOp {
76 fn encode(pin: Pin, op: Self) -> i32 {
78 assert!(op != Self::ClearAll);
79 (pin.0 as i32) * 100 + (op as i32)
80 }
81}
82
83#[derive(Default)]
88pub struct MockPins {
89 reads: VecDeque<(Pin, bool)>,
91
92 trace: Vec<i32>,
96}
97
98impl MockPins {
99 pub fn inject_read(&mut self, pin: Pin, high: bool) {
101 self.reads.push_back((pin, high));
102 }
103
104 pub fn trace(&self) -> &[i32] {
106 &self.trace
107 }
108}
109
110impl Pins for MockPins {
111 fn as_any(&self) -> &dyn Any {
112 self
113 }
114
115 fn as_any_mut(&mut self) -> &mut dyn Any {
116 self
117 }
118
119 fn setup(&mut self, pin: Pin, mode: PinMode) -> io::Result<()> {
120 let datum = match mode {
121 PinMode::In => MockOp::encode(pin, MockOp::SetupIn),
122 PinMode::InPullDown => MockOp::encode(pin, MockOp::SetupInPullDown),
123 PinMode::InPullUp => MockOp::encode(pin, MockOp::SetupInPullUp),
124 PinMode::Out => MockOp::encode(pin, MockOp::SetupOut),
125 };
126 self.trace.push(datum);
127 Ok(())
128 }
129
130 fn clear(&mut self, pin: Pin) -> io::Result<()> {
131 self.trace.push(MockOp::encode(pin, MockOp::Clear));
132 Ok(())
133 }
134
135 fn clear_all(&mut self) -> io::Result<()> {
136 self.trace.push(MockOp::ClearAll as i32);
137 Ok(())
138 }
139
140 fn read(&mut self, pin: Pin) -> io::Result<bool> {
141 match self.reads.pop_front() {
142 Some((read_pin, high)) if read_pin == pin => {
143 let op = if high { MockOp::ReadHigh } else { MockOp::ReadLow };
144 self.trace.push(MockOp::encode(pin, op));
145 Ok(high)
146 }
147 Some((read_pin, _)) => Err(io::Error::new(
148 io::ErrorKind::InvalidData,
149 format!("Want to read pin {} but next mock read is for pin {}", pin.0, read_pin.0),
150 )),
151 None => Err(io::Error::new(
152 io::ErrorKind::InvalidData,
153 format!("No mock read available for pin {}", pin.0),
154 )),
155 }
156 }
157
158 fn write(&mut self, pin: Pin, v: bool) -> io::Result<()> {
159 let op = if v { MockOp::WriteHigh } else { MockOp::WriteLow };
160 self.trace.push(MockOp::encode(pin, op));
161 Ok(())
162 }
163}