1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Describes generic devices such as `GPIODevice` and `CompositeDevice`

use rppal::gpio::{Gpio, Level, Pin};

/// Represents a single device of any type; GPIO-based, SPI-based, I2C-based,
/// etc.  It defines the basic services applicable to all devices
pub trait Device {
    /// Shut down the device and release all associated resources.
    fn close(self);

    /// Returns ``True`` if the device is currently active and ``False`` otherwise.
    fn is_active(&self) -> bool;
}

#[macro_export]
macro_rules! impl_device {
    () => {
        /// Returns ``True`` if the device is currently active and ``False`` otherwise.
        pub fn is_active(&self) -> bool {
            self.value()
        }
        /// Shut down the device and release all associated resources.
        pub fn close(self) {
            drop(self)
        }
    };
}

/// Represents a generic GPIO device and provides the services common to all single-pin GPIO devices
#[derive(Debug)]
pub struct GpioDevice {
    pin: Pin,
    active_state: bool,
    inactive_state: bool,
}

macro_rules! impl_gpio_device {
    () => {
        /// The `Pin` that the device is connected to.
        pub fn pin(&self) -> u8 {
            self.pin.pin()
        }
    };
}

impl GpioDevice {
    /// Returns a GpioDevice with the pin number given
    /// # Arguments
    ///
    /// * `pin` - The GPIO pin which the device is attached to
    pub fn new(pin: u8) -> GpioDevice {
        match Gpio::new() {
            Err(e) => panic!("{:?}", e),
            Ok(gpio) => match gpio.get(pin) {
                Err(e) => panic!("{:?}", e),
                Ok(pin) => GpioDevice {
                    pin,
                    active_state: true,
                    inactive_state: false,
                },
            },
        }
    }

    /// Returns a value representing the device's state.
    pub fn value(&self) -> bool {
        self.state_to_value()
    }

    fn state_to_value(&self) -> bool {
        match self.pin.read() {
            Level::High => self.active_state,
            Level::Low => !self.active_state,
        }
    }

    impl_device!();
    impl_gpio_device!();
}