rust_gpiozero/input_devices.rs
1//! Input device component interfaces for devices such as `Button`
2use rppal::gpio::{Gpio, InputPin, Level, Trigger};
3use std::time::Duration;
4
5/// Represents a generic GPIO input device.
6#[derive(Debug)]
7pub struct InputDevice {
8 pin: InputPin,
9 active_state: bool,
10 inactive_state: bool,
11}
12
13impl InputDevice {
14 /// Returns an InputDevice with the pin number given with the pin pulled to low by default
15 /// `is_active` property is adjusted accordingly so that
16 /// ``True`` still means active regardless of the :attr:`pull_up` setting
17 /// # Arguments
18 ///
19 /// * `pin` - The GPIO pin which the device is attached to
20 ///
21 pub fn new(pin: u8) -> InputDevice {
22 match Gpio::new() {
23 Err(e) => panic!("{:?}", e),
24 Ok(gpio) => match gpio.get(pin) {
25 Err(e) => panic!("{:?}", e),
26 Ok(pin) => InputDevice {
27 pin: pin.into_input_pulldown(),
28 active_state: true,
29 inactive_state: false,
30 },
31 },
32 }
33 }
34 /// Returns an InputDevice with the pin number given with the pin pulled high with an internal resistor by default
35 /// `is_active` property is adjusted accordingly so that
36 /// ``True`` still means active regardless of the :attr:`pull_up` setting
37 /// # Arguments
38 ///
39 /// * `pin` - The GPIO pin which the device is attached to
40 ///
41 pub fn new_with_pullup(pin: u8) -> InputDevice {
42 match Gpio::new() {
43 Err(e) => panic!("{:?}", e),
44 Ok(gpio) => match gpio.get(pin) {
45 Err(e) => panic!("{:?}", e),
46 Ok(pin) => InputDevice {
47 pin: pin.into_input_pullup(),
48 active_state: false,
49 inactive_state: true,
50 },
51 },
52 }
53 }
54
55 impl_device!();
56 impl_gpio_device!();
57 impl_io_device!();
58}
59
60macro_rules! impl_events_mixin {
61 () => {
62 /// Pause the program until the device is activated, or the timeout is reached.
63 fn wait_for(&mut self, timeout: Option<f32>, active: bool) {
64 match timeout {
65 None => {
66 if active {
67 self.pin.set_interrupt(Trigger::RisingEdge).unwrap();
68 self.pin.poll_interrupt(true, None).unwrap();
69 } else {
70 self.pin.set_interrupt(Trigger::FallingEdge).unwrap();
71 self.pin.poll_interrupt(true, None).unwrap();
72 }
73 }
74 Some(n) => {
75 if active {
76 self.pin.set_interrupt(Trigger::RisingEdge).unwrap();
77 self.pin
78 .poll_interrupt(true, Some(Duration::from_millis((n * 1000.0) as u64)))
79 .unwrap();
80 } else {
81 self.pin.set_interrupt(Trigger::FallingEdge).unwrap();
82 self.pin
83 .poll_interrupt(true, Some(Duration::from_millis((n * 1000.0) as u64)))
84 .unwrap();
85 }
86 }
87 }
88 }
89 };
90}
91
92/// Represents a generic input device with typical on/off behaviour.
93/// Adds machinery to fire the active and inactive events for devices
94/// that operate in a typical digital manner: straight forward on / off
95/// states with (reasonably) clean transitions between the two.
96#[derive(Debug)]
97pub struct DigitalInputDevice {
98 pin: InputPin,
99 active_state: bool,
100 inactive_state: bool,
101 bounce_time: Option<f32>,
102}
103
104impl DigitalInputDevice {
105 /// Returns a DigitalInputDevice with the pin number given with the pin pulled to low by default
106 /// `is_active` property is adjusted accordingly so that
107 /// ``True`` still means active regardless of the :attr:`pull_up` setting
108 /// # Arguments
109 ///
110 /// * `pin` - The GPIO pin which the device is attached to
111 /// # Note: BCM pins 2 and 3 are i2c SDA and SCL respectively and include a fixed, 1.8 kohms pull-up to 3.3v
112 /// These pins are not suitable for use where no pullup resistor is required
113 /// Source: https://pinout.xyz/pinout/pin5_gpio3
114 pub fn new(pin: u8) -> DigitalInputDevice {
115 match Gpio::new() {
116 Err(e) => panic!("{:?}", e),
117 Ok(gpio) => match gpio.get(pin) {
118 Err(e) => panic!("{:?}", e),
119 Ok(pin) => DigitalInputDevice {
120 pin: pin.into_input_pulldown(),
121 active_state: true,
122 inactive_state: false,
123 bounce_time: None,
124 },
125 },
126 }
127 }
128 /// Returns a DigitalInputDevice with the pin number given with the pin pulled high with an internal resistor by default
129 /// `is_active` property is adjusted accordingly so that
130 /// ``True`` still means active regardless of the :attr:`pull_up` setting
131 /// # Arguments
132 ///
133 /// * `pin` - The GPIO pin which the device is attached to
134 ///
135 pub fn new_with_pullup(pin: u8) -> DigitalInputDevice {
136 match Gpio::new() {
137 Err(e) => panic!("{:?}", e),
138 Ok(gpio) => match gpio.get(pin) {
139 Err(e) => panic!("{:?}", e),
140 Ok(pin) => DigitalInputDevice {
141 pin: pin.into_input_pullup(),
142 active_state: false,
143 inactive_state: true,
144 bounce_time: None,
145 },
146 },
147 }
148 }
149
150 impl_device!();
151 impl_gpio_device!();
152 impl_io_device!();
153 impl_events_mixin!();
154
155 /// Pause the program until the device is deactivated, or the timeout is reached.
156 pub fn wait_for_inactive(&mut self, timeout: Option<f32>) {
157 self.wait_for(timeout, false)
158 }
159
160 /// Pause the program until the device is activated, or the timeout is reached.
161 pub fn wait_for_active(&mut self, timeout: Option<f32>) {
162 self.wait_for(timeout, true)
163 }
164}
165
166/// Represents a simple push button or switch.
167/// Connect one side of the button to a ground pin, and the other to any GPIO pin. The GPIO pin will be pulled high by default.
168/// Alternatively, connect one side of the button to the 3V3 pin, and the other to any GPIO pin,
169/// and then create a Button instance with Button::new_with_pulldown
170pub struct Button {
171 pin: InputPin,
172 active_state: bool,
173 inactive_state: bool,
174 // FIXME: Implement debouncing
175 #[allow(dead_code)]
176 bounce_time: Option<f32>,
177}
178
179impl Button {
180 /// Returns a Button with the pin number given and the pin pulled high with an internal resistor by default
181 /// * `pin` - The GPIO pin which the device is attached to
182 pub fn new(pin: u8) -> Button {
183 match Gpio::new() {
184 Err(e) => panic!("{:?}", e),
185 Ok(gpio) => match gpio.get(pin) {
186 Err(e) => panic!("{:?}", e),
187 Ok(pin) => Button {
188 pin: pin.into_input_pullup(),
189 active_state: false,
190 inactive_state: true,
191 bounce_time: None,
192 },
193 },
194 }
195 }
196 /// Returns a Button with the pin number given and the pin pulled down with an internal resistor by default
197 /// * `pin` - The GPIO pin which the device is attached to
198 pub fn new_with_pulldown(pin: u8) -> Button {
199 match Gpio::new() {
200 Err(e) => panic!("{:?}", e),
201 Ok(gpio) => match gpio.get(pin) {
202 Err(e) => panic!("{:?}", e),
203 Ok(pin) => Button {
204 pin: pin.into_input_pulldown(),
205 active_state: true,
206 inactive_state: false,
207 bounce_time: None,
208 },
209 },
210 }
211 }
212
213 impl_device!();
214 impl_gpio_device!();
215 impl_io_device!();
216 impl_events_mixin!();
217
218 //// Pause the program until the device is deactivated, or the timeout is reached.
219 /// * `timeout` - Number of seconds to wait before proceeding. If this is None, then wait indefinitely until the device is inactive.
220 pub fn wait_for_release(&mut self, timeout: Option<f32>) {
221 self.wait_for(timeout, false)
222 }
223
224 /// Pause the program until the device is activated, or the timeout is reached.
225 /// * `timeout` - Number of seconds to wait before proceeding. If this is None, then wait indefinitely until the device is active.
226 pub fn wait_for_press(&mut self, timeout: Option<f32>) {
227 self.wait_for(timeout, true)
228 }
229}