linux_embedded_hal/
sysfs_pin.rs

1//! Implementation of [`embedded-hal`] digital input/output traits using a Linux Sysfs pin
2//!
3//! [`embedded-hal`]: https://docs.rs/embedded-hal
4
5use std::fmt;
6use std::path::Path;
7
8/// Newtype around [`sysfs_gpio::Pin`] that implements the `embedded-hal` traits
9///
10/// [`sysfs_gpio::Pin`]: https://docs.rs/sysfs_gpio/0.6.0/sysfs_gpio/struct.Pin.html
11pub struct SysfsPin(pub sysfs_gpio::Pin);
12
13impl SysfsPin {
14    /// See [`sysfs_gpio::Pin::new`][0] for details.
15    ///
16    /// [0]: https://docs.rs/sysfs_gpio/0.6.0/sysfs_gpio/struct.Pin.html#method.new
17    pub fn new(pin_num: u64) -> Self {
18        SysfsPin(sysfs_gpio::Pin::new(pin_num))
19    }
20
21    /// See [`sysfs_gpio::Pin::from_path`][0] for details.
22    ///
23    /// [0]: https://docs.rs/sysfs_gpio/0.6.0/sysfs_gpio/struct.Pin.html#method.from_path
24    pub fn from_path<P>(path: P) -> sysfs_gpio::Result<Self>
25    where
26        P: AsRef<Path>,
27    {
28        sysfs_gpio::Pin::from_path(path).map(SysfsPin)
29    }
30
31    /// Convert this pin to an input pin
32    pub fn into_input_pin(self) -> Result<SysfsPin, sysfs_gpio::Error> {
33        self.set_direction(sysfs_gpio::Direction::In)?;
34        Ok(self)
35    }
36
37    /// Convert this pin to an output pin
38    pub fn into_output_pin(
39        self,
40        state: embedded_hal::digital::PinState,
41    ) -> Result<SysfsPin, sysfs_gpio::Error> {
42        self.set_direction(match state {
43            embedded_hal::digital::PinState::High => sysfs_gpio::Direction::High,
44            embedded_hal::digital::PinState::Low => sysfs_gpio::Direction::Low,
45        })?;
46        Ok(self)
47    }
48}
49
50/// Error type wrapping [sysfs_gpio::Error](sysfs_gpio::Error) to implement [embedded_hal::digital::Error]
51#[derive(Debug)]
52pub struct SysfsPinError {
53    err: sysfs_gpio::Error,
54}
55
56impl SysfsPinError {
57    /// Fetch inner (concrete) [`sysfs_gpio::Error`]
58    pub fn inner(&self) -> &sysfs_gpio::Error {
59        &self.err
60    }
61}
62
63impl From<sysfs_gpio::Error> for SysfsPinError {
64    fn from(err: sysfs_gpio::Error) -> Self {
65        Self { err }
66    }
67}
68
69impl fmt::Display for SysfsPinError {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        write!(f, "{}", self.err)
72    }
73}
74
75impl std::error::Error for SysfsPinError {
76    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
77        Some(&self.err)
78    }
79}
80
81impl embedded_hal::digital::Error for SysfsPinError {
82    fn kind(&self) -> embedded_hal::digital::ErrorKind {
83        use embedded_hal::digital::ErrorKind;
84        ErrorKind::Other
85    }
86}
87
88impl embedded_hal::digital::ErrorType for SysfsPin {
89    type Error = SysfsPinError;
90}
91
92impl embedded_hal::digital::OutputPin for SysfsPin {
93    fn set_low(&mut self) -> Result<(), Self::Error> {
94        if self.0.get_active_low().map_err(SysfsPinError::from)? {
95            self.0.set_value(1).map_err(SysfsPinError::from)
96        } else {
97            self.0.set_value(0).map_err(SysfsPinError::from)
98        }
99    }
100
101    fn set_high(&mut self) -> Result<(), Self::Error> {
102        if self.0.get_active_low().map_err(SysfsPinError::from)? {
103            self.0.set_value(0).map_err(SysfsPinError::from)
104        } else {
105            self.0.set_value(1).map_err(SysfsPinError::from)
106        }
107    }
108}
109
110impl embedded_hal::digital::InputPin for SysfsPin {
111    fn is_high(&mut self) -> Result<bool, Self::Error> {
112        if !self.0.get_active_low().map_err(SysfsPinError::from)? {
113            self.0
114                .get_value()
115                .map(|val| val != 0)
116                .map_err(SysfsPinError::from)
117        } else {
118            self.0
119                .get_value()
120                .map(|val| val == 0)
121                .map_err(SysfsPinError::from)
122        }
123    }
124
125    fn is_low(&mut self) -> Result<bool, Self::Error> {
126        self.is_high().map(|val| !val).map_err(SysfsPinError::from)
127    }
128}
129
130impl core::ops::Deref for SysfsPin {
131    type Target = sysfs_gpio::Pin;
132
133    fn deref(&self) -> &Self::Target {
134        &self.0
135    }
136}
137
138impl core::ops::DerefMut for SysfsPin {
139    fn deref_mut(&mut self) -> &mut Self::Target {
140        &mut self.0
141    }
142}