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}