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}