avr_tester/pins/
digital_pin.rs

1use crate::*;
2
3/// Provides access to a digital pin, e.g. `PD4`.
4pub struct DigitalPin<'a> {
5    avr: &'a mut AvrTester,
6    port: char,
7    pin: u8,
8}
9
10impl<'a> DigitalPin<'a> {
11    pub(crate) fn new(avr: &'a mut AvrTester, port: char, pin: u8) -> Self {
12        Self { avr, port, pin }
13    }
14
15    /// Changes pin's state to low or high.
16    pub fn set(&mut self, high: bool) {
17        self.avr.sim().set_digital_pin(self.port, self.pin, high);
18    }
19
20    /// Changes pin's state to low.
21    pub fn set_low(&mut self) {
22        self.set(false);
23    }
24
25    /// Changes pin's state to high.
26    pub fn set_high(&mut self) {
27        self.set(true);
28    }
29
30    /// Changes pin's state from low to high or from high to low.
31    pub fn toggle(&mut self) {
32        if self.is_low() {
33            self.set_high();
34        } else {
35            self.set_low();
36        }
37    }
38
39    /// Returns whether pin's state is low.
40    pub fn is_low(&mut self) -> bool {
41        !self.is_high()
42    }
43
44    /// Returns whether pin's state is high.
45    pub fn is_high(&mut self) -> bool {
46        self.avr.sim().get_digital_pin(self.port, self.pin)
47    }
48
49    /// Asserts that pin's state is high or low.
50    #[track_caller]
51    pub fn assert(&mut self, high: bool) {
52        if high {
53            self.assert_high();
54        } else {
55            self.assert_low();
56        }
57    }
58
59    /// Asserts that pin's state is low.
60    #[track_caller]
61    pub fn assert_low(&mut self) {
62        assert!(self.is_low(), "{} is not low", self.name());
63    }
64
65    /// Asserts that pin's state is high.
66    #[track_caller]
67    pub fn assert_high(&mut self) {
68        assert!(self.is_high(), "{} is not high", self.name());
69    }
70
71    /// Waits until pin switches state (e.g. from low to high or from high to
72    /// low).
73    ///
74    /// Returns duration it took for the pin to switch state.
75    pub fn pulse_in(&mut self) -> AvrDuration {
76        let mut tt = AvrDuration::zero(self.avr);
77        let state = self.is_high();
78
79        while self.is_high() == state {
80            tt += self.avr.run();
81        }
82
83        tt
84    }
85
86    /// Waits until pin becomes high; if the pin is already high, exits
87    /// immediately.
88    ///
89    /// Returns duration it took for the pin to get high.
90    pub fn wait_while_low(&mut self) -> AvrDuration {
91        let mut tt = AvrDuration::zero(self.avr);
92
93        while self.is_low() {
94            tt += self.avr.run();
95        }
96
97        tt
98    }
99
100    /// Waits until pin becomes high or timeout is reached; if the pin is
101    /// already high, exits immediately.
102    ///
103    /// Returns a result containing the amount of time that has passed
104    /// for the device.
105    ///
106    /// If the timeout was reached before the pin state changed, the
107    /// duration will be contained in the `Err` variant, otherwise
108    /// the `Ok` variant contains the duration it took for the pin to
109    /// get high.
110    pub fn wait_while_low_timeout(
111        &mut self,
112        timeout: AvrDuration,
113    ) -> Result<AvrDuration, AvrDuration> {
114        let mut tt = AvrDuration::zero(self.avr);
115
116        while self.is_low() {
117            if tt >= timeout {
118                return Err(tt);
119            }
120            tt += self.avr.run();
121        }
122
123        Ok(tt)
124    }
125
126    /// Waits until pin becomes low; if the pin is already low, exits
127    /// immediately.
128    ///
129    /// Returns duration it took for the pin to get low.
130    pub fn wait_while_high(&mut self) -> AvrDuration {
131        let mut tt = AvrDuration::zero(self.avr);
132
133        while self.is_high() {
134            tt += self.avr.run();
135        }
136
137        tt
138    }
139
140    /// Waits until pin becomes low or timeout is reached; if the pin is
141    /// already low, exits immediately.
142    ///
143    /// Returns a result containing the amount of time that has passed
144    /// for the device.
145    ///
146    /// If the timeout was reached before the pin state changed, the
147    /// duration will be contained in the `Err` variant, otherwise
148    /// the `Ok` variant contains the duration it took for the pin to
149    /// get low.
150    pub fn wait_while_high_timeout(
151        &mut self,
152        timeout: AvrDuration,
153    ) -> Result<AvrDuration, AvrDuration> {
154        let mut tt = AvrDuration::zero(self.avr);
155
156        while self.is_high() {
157            if tt >= timeout {
158                return Err(tt);
159            }
160            tt += self.avr.run();
161        }
162
163        Ok(tt)
164    }
165
166    /// Return pin's name, e.g. `PC6`.
167    pub fn name(&self) -> String {
168        format!("P{}{}", self.port, self.pin)
169    }
170}
171
172/// Asynchronous equivalent of [`DigitalPin`].
173///
174/// See [`avr_rt()`] for more details.
175pub struct DigitalPinAsync {
176    port: char,
177    pin: u8,
178}
179
180impl DigitalPinAsync {
181    pub(crate) fn new(port: char, pin: u8) -> Self {
182        Self { port, pin }
183    }
184
185    /// Asynchronous equivalent of [`DigitalPin::set()`].
186    pub fn set(&self, high: bool) {
187        ComponentRuntime::with(|rt| {
188            rt.sim().set_digital_pin(self.port, self.pin, high);
189        })
190    }
191
192    /// Asynchronous equivalent of [`DigitalPin::set_low()`].
193    pub fn set_low(&self) {
194        self.set(false);
195    }
196
197    /// Asynchronous equivalent of [`DigitalPin::set_high()`].
198    pub fn set_high(&self) {
199        self.set(true);
200    }
201
202    /// Asynchronous equivalent of [`DigitalPin::toggle()`].
203    pub fn toggle(&self) {
204        if self.is_low() {
205            self.set_high();
206        } else {
207            self.set_low();
208        }
209    }
210
211    /// Asynchronous equivalent of [`DigitalPin::is_low()`].
212    pub fn is_low(&self) -> bool {
213        !self.is_high()
214    }
215
216    /// Asynchronous equivalent of [`DigitalPin::is_high()`].
217    pub fn is_high(&self) -> bool {
218        ComponentRuntime::with(|rt| {
219            rt.sim().get_digital_pin(self.port, self.pin)
220        })
221    }
222
223    /// Asynchronous equivalent of [`DigitalPin::assert_low()`].
224    #[track_caller]
225    pub fn assert_low(&self) {
226        assert!(self.is_low(), "{} is not low", self.name());
227    }
228
229    /// Asynchronous equivalent of [`DigitalPin::assert_high()`].
230    #[track_caller]
231    pub fn assert_high(&self) {
232        assert!(self.is_high(), "{} is not high", self.name());
233    }
234
235    /// Asynchronous equivalent of [`DigitalPin::pulse_in()`].
236    pub async fn pulse_in(&self) -> AvrDuration {
237        let mut tt = ComponentRuntime::with(|rt| {
238            AvrDuration::new(rt.clock_frequency(), 0)
239        });
240        let state = self.is_high();
241
242        while self.is_high() == state {
243            tt += avr_rt().run().await;
244        }
245
246        tt
247    }
248
249    /// Asynchronous equivalent of [`DigitalPin::wait_while_low()`].
250    pub async fn wait_while_low(&self) -> AvrDuration {
251        let mut tt = ComponentRuntime::with(|rt| {
252            AvrDuration::new(rt.clock_frequency(), 0)
253        });
254
255        while self.is_low() {
256            tt += avr_rt().run().await;
257        }
258
259        tt
260    }
261
262    /// Asynchronous equivalent of [`DigitalPin::wait_while_high()`].
263    pub async fn wait_while_high(&self) -> AvrDuration {
264        let mut tt = ComponentRuntime::with(|rt| {
265            AvrDuration::new(rt.clock_frequency(), 0)
266        });
267
268        while self.is_high() {
269            tt += avr_rt().run().await;
270        }
271
272        tt
273    }
274
275    /// Asynchronous equivalent of [`DigitalPin::name()`].
276    pub fn name(&self) -> String {
277        format!("P{}{}", self.port, self.pin)
278    }
279}