switch_hal/
lib.rs

1#![no_std]
2
3mod input;
4mod output;
5
6pub mod mock;
7
8/// Represents an input switch, such as a button or a switch
9pub trait InputSwitch {
10    type Error;
11
12    /// Returns true if the swich has been activated, otherwise false
13    /// i.e. if a button is currently pressed, returns true
14    ///
15    /// # Examples
16    ///
17    /// ```
18    /// # use switch_hal::mock;
19    /// use switch_hal::{InputSwitch, OutputSwitch, Switch, IntoSwitch};
20    /// # let pin = mock::Pin::with_state(mock::State::High);
21    /// # let mut status_led = mock::Pin::new().into_active_high_switch();
22    /// let button = pin.into_active_low_switch();
23    /// match button.is_active() {
24    ///     Ok(true) => { status_led.on().ok(); }
25    ///     Ok(false) => { status_led.off().ok(); }
26    ///     Err(_) => { panic!("Failed to read button state"); }
27    /// }
28    /// ```
29    fn is_active(&self) -> Result<bool, Self::Error>;
30}
31
32/// Represents an output switch, such as a LED "switch" or transitor
33pub trait OutputSwitch {
34    type Error;
35
36    /// Turns the switch on
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// # use switch_hal::mock;
42    /// use switch_hal::{OutputSwitch, Switch, IntoSwitch};
43    /// # let pin = mock::Pin::new();
44    /// let mut led = pin.into_active_high_switch();
45    /// led.on().ok();
46    /// ```
47    fn on(&mut self) -> Result<(), Self::Error>;
48
49    /// Turns the switch off
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// # use switch_hal::mock;
55    /// use switch_hal::{OutputSwitch, Switch, IntoSwitch};
56    /// # let pin = mock::Pin::new();
57    /// let mut led = pin.into_active_high_switch();
58    /// led.off().ok();
59    /// ```
60    fn off(&mut self) -> Result<(), Self::Error>;
61}
62
63/// Toggles the switch from it's current state to it's opposite state.
64///
65/// # Notes
66/// This is only available if the underlying hal has implemented [ToggleableOutputPin](embedded_hal::digital::v2::ToggleableOutputPin)
67pub trait ToggleableOutputSwitch {
68    type Error;
69
70    /// Toggles the current state of the [OutputSwitch](OutputSwitch)
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// # use switch_hal::mock;
76    /// use switch_hal::{OutputSwitch, ToggleableOutputSwitch, Switch, IntoSwitch};
77    /// # let pin = mock::Pin::new();
78    /// let mut led = pin.into_active_high_switch();
79    /// led.toggle().ok();
80    /// ```
81    fn toggle(&mut self) -> Result<(), Self::Error>;
82}
83
84/// Checks current switch state
85///
86/// # Notes
87/// This is only available if the underlying hal has implemented [StatefulOutputPin](embedded_hal::digital::v2::StatefulOutputPin)
88pub trait StatefulOutputSwitch {
89    type Error;
90
91    /// Checks whether the switch is on
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// # use switch_hal::mock;
97    /// use switch_hal::{OutputSwitch, Switch, StatefulOutputSwitch, IntoSwitch};
98    /// # let pin = mock::Pin::new();
99    /// let mut led = pin.into_active_high_switch();
100    /// led.off().ok();
101    /// assert!(!led.is_on().unwrap());
102    /// ```
103    fn is_on(&mut self) -> Result<bool, Self::Error>;
104
105    /// Checks whether the switch is off
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// # use switch_hal::mock;
111    /// use switch_hal::{OutputSwitch, Switch, StatefulOutputSwitch, IntoSwitch};
112    /// # let pin = mock::Pin::new();
113    /// let mut led = pin.into_active_high_switch();
114    /// led.off().ok();
115    /// assert!(led.is_off().unwrap());
116    /// ```
117    fn is_off(&mut self) -> Result<bool, Self::Error>;
118}
119
120/// Zero sized struct for signaling to [Switch](struct.Switch.html) that it is active high
121pub struct ActiveHigh;
122/// Zero sized struct for signaling to [Switch](struct.Switch.html) that it is active low
123pub struct ActiveLow;
124
125use core::marker::PhantomData;
126
127/// Concrete implementation for [InputSwitch](trait.InputSwitch.html) and [OutputSwitch](trait.OutputSwitch.html)
128///
129/// # Type Params
130/// - `IoPin` must be a type that implements either of the [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin) traits.
131/// - `ActiveLevel` indicates whether the `Switch` is [ActiveHigh](ActiveHigh) or [ActiveLow](ActiveLow).
132///     `ActiveLevel` is not actually stored in the struct.
133///     It's [PhantomData](core::marker::PhantomData) used to indicate which implementation to use.
134pub struct Switch<IoPin, ActiveLevel> {
135    pin: IoPin,
136    active: PhantomData<ActiveLevel>,
137}
138
139impl<IoPin, ActiveLevel> Switch<IoPin, ActiveLevel> {
140    /// Constructs a new [Switch](struct.Switch.html) from a concrete implementation of an
141    /// [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin)
142    ///
143    /// **Prefer the [IntoSwitch](trait.IntoSwitch.html) trait over calling [new](#method.new) directly.**
144    ///
145    /// # Examples
146    ///
147    /// Active High
148    ///
149    /// ```
150    /// # use switch_hal::mock;
151    /// use switch_hal::{ActiveHigh, OutputSwitch, Switch};
152    /// # let pin = mock::Pin::new();
153    /// let mut led = Switch::<_, ActiveHigh>::new(pin);
154    /// ```
155    ///
156    /// ActiveLow
157    ///
158    /// ```
159    /// # use switch_hal::mock;
160    /// use switch_hal::{ActiveLow, OutputSwitch, Switch};
161    /// # let pin = mock::Pin::new();
162    /// let mut led = Switch::<_, ActiveLow>::new(pin);
163    /// ```
164    ///
165    /// stm32f3xx-hal
166    ///
167    /// ```ignore
168    /// // Example for the stm32f303
169    /// use stm32f3xx_hal::gpio::gpioe;
170    /// use stm32f3xx_hal::gpio::{PushPull, Output};
171    /// use stm32f3xx_hal::stm32;
172    ///
173    /// use switch_hal::{ActiveHigh, Switch};
174    ///
175    /// let device_periphs = stm32::Peripherals::take().unwrap();
176    /// let gpioe = device_periphs.GPIOE.split(&mut reset_control_clock.ahb);
177    ///
178    /// let led = Switch::<_, ActiveHigh>::new(
179    ///     gpioe
180    ///     .pe9
181    ///     .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper)
182    /// )
183    /// ```
184    pub fn new(pin: IoPin) -> Self {
185        Switch {
186            pin: pin,
187            active: PhantomData::<ActiveLevel>,
188        }
189    }
190
191    /// Consumes the [Switch](struct.Switch.html) and returns the underlying [InputPin](embedded_hal::digital::v2::InputPin) or [OutputPin](embedded_hal::digital::v2::OutputPin).
192    ///
193    /// This is useful fore retrieving the underlying pin to use it for a different purpose.
194    ///
195    /// # Examples
196    ///
197    /// ```
198    /// # use switch_hal::mock;
199    /// use switch_hal::{OutputSwitch, Switch, IntoSwitch};
200    /// # let pin = mock::Pin::new();
201    /// let mut led = pin.into_active_high_switch();
202    /// led.on().ok();
203    /// let mut pin = led.into_pin();
204    /// // do something else with the pin
205    /// ```
206    pub fn into_pin(self) -> IoPin {
207        self.pin
208    }
209}
210
211/// Convenience functions for converting [InputPin](embedded_hal::digital::v2::InputPin)
212/// and [OutputPin](embedded_hal::digital::v2::OutputPin) to a [Switch](struct.Switch.html).
213///
214/// The type of [Switch](struct.Switch.html) returned,
215/// [InputSwitch](trait.InputSwitch.html) or [OutputSwitch](trait.OutputSwitch.html) is
216/// determined by whether the `IoPin` being consumed is an [InputPin](embedded_hal::digital::v2::InputPin)
217/// or [OutputPin](embedded_hal::digital::v2::OutputPin).
218pub trait IntoSwitch {
219
220    /// Consumes the `IoPin` returning a [Switch](struct.Switch.html) of the appropriate `ActiveLevel`.
221    ///
222    /// This method exists so other, more convenient functions, can have blanket implementations.  
223    /// Prefer [into_active_low_switch](#method.into_active_low_switch) and [into_active_high_switch](#method.into_active_high_switch).
224    ///
225    /// # Examples
226    ///
227    /// ## Active High
228    ///
229    /// ```
230    /// # use switch_hal::mock;
231    /// use switch_hal::{ActiveHigh, OutputSwitch, IntoSwitch};
232    /// # let pin = mock::Pin::new();
233    /// let led = pin.into_switch::<ActiveHigh>();
234    /// ```
235    ///
236    /// ## Active Low
237    ///
238    /// ```
239    /// # use switch_hal::mock;
240    /// use switch_hal::{ActiveLow, InputSwitch, IntoSwitch};
241    /// # let pin = mock::Pin::new();
242    /// let button = pin.into_switch::<ActiveLow>();
243    /// ```
244    fn into_switch<ActiveLevel>(self) -> Switch<Self, ActiveLevel>
245    where
246        Self: core::marker::Sized;
247
248    /// Consumes the `IoPin` returning a `Switch<IoPin, ActiveLow>`.
249    ///
250    /// # Examples
251    ///
252    /// ```
253    /// # use switch_hal::mock;
254    /// use switch_hal::IntoSwitch;
255    /// # let pin = mock::Pin::new();
256    /// let led = pin.into_active_low_switch();
257    /// ```
258    fn into_active_low_switch(self) -> Switch<Self, ActiveLow>
259    where
260        Self: core::marker::Sized,
261    {
262        self.into_switch::<ActiveLow>()
263    }
264
265    /// Consumes the `IoPin` returning a `Switch<IoPin, ActiveHigh>`.
266    ///
267    /// # Examples
268    ///
269    /// ```
270    /// # use switch_hal::mock;
271    /// use switch_hal::IntoSwitch;
272    /// # let pin = mock::Pin::new();
273    /// let button = pin.into_active_high_switch();
274    /// ```
275    fn into_active_high_switch(self) -> Switch<Self, ActiveHigh>
276    where
277        Self: core::marker::Sized,
278    {
279        self.into_switch::<ActiveHigh>()
280    }
281}
282
283impl<T> IntoSwitch for T {
284    fn into_switch<ActiveLevel>(self) -> Switch<Self, ActiveLevel> {
285        Switch::<Self, ActiveLevel>::new(self)
286    }
287}