1use std::{fs, io};
11use std::io::{Read, Seek, SeekFrom, Write};
12use super::{GpioIn, GpioOut, GpioValue};
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15enum GpioDirection {
16 Input,
17 Output,
18}
19
20#[inline]
21fn export_gpio_if_unexported(gpio_num: u16) -> io::Result<()> {
22 if let Err(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", gpio_num)) {
24 let mut export_fp = fs::File::create("/sys/class/gpio/export")?;
25 write!(export_fp, "{}", gpio_num)?;
26 }
27
28 fs::File::create(format!("/sys/class/gpio/gpio{}/active_low", gpio_num))?.write_all(b"0")
30}
31
32#[inline]
33fn set_gpio_direction(gpio_num: u16, direction: GpioDirection) -> io::Result<()> {
34 fs::File::create(format!("/sys/class/gpio/gpio{}/direction", gpio_num))?.write_all(
35 match direction {
36 GpioDirection::Input => b"in",
37 GpioDirection::Output => b"out",
38 },
39 )
40}
41
42#[inline]
43fn open_gpio(gpio_num: u16, direction: GpioDirection) -> io::Result<fs::File> {
44 let p = format!("/sys/class/gpio/gpio{}/value", gpio_num);
45
46 match direction {
47 GpioDirection::Input => fs::File::open(p),
48 GpioDirection::Output => fs::File::create(p),
49 }
50}
51
52#[derive(Debug)]
53struct SysFsGpio {
54 gpio_num: u16,
55 sysfp: fs::File,
56}
57
58impl SysFsGpio {
59 fn open(gpio_num: u16, direction: GpioDirection) -> io::Result<SysFsGpio> {
60 export_gpio_if_unexported(gpio_num)?;
61
62 fs::File::create(format!("/sys/class/gpio/gpio{}/active_low", gpio_num))?.write_all(b"0")?;
65
66 set_gpio_direction(gpio_num, direction)?;
67
68 Ok(SysFsGpio {
70 gpio_num,
71 sysfp: open_gpio(gpio_num, direction)?,
72 })
73 }
74
75 #[inline]
76 fn set_direction(&mut self, direction: GpioDirection) -> io::Result<()> {
77 set_gpio_direction(self.gpio_num, direction)?;
78 self.sysfp = open_gpio(self.gpio_num, direction)?;
79
80 Ok(())
81 }
82}
83
84impl Drop for SysFsGpio {
85 #[inline]
86 fn drop(&mut self) {
87 let unexport_fp = fs::File::create("/sys/class/gpio/unexport");
90
91 if let Ok(mut fp) = unexport_fp {
92 write!(fp, "{}\n", self.gpio_num).ok();
93 }
94 }
95}
96
97#[derive(Debug)]
99pub struct SysFsGpioOutput {
100 gpio: SysFsGpio,
101}
102
103impl SysFsGpioOutput {
104 #[inline]
106 pub fn open(gpio_num: u16) -> io::Result<SysFsGpioOutput> {
107 Ok(SysFsGpioOutput {
108 gpio: SysFsGpio::open(gpio_num, GpioDirection::Output)?,
109 })
110 }
111
112 #[inline]
113 pub fn into_input(mut self) -> io::Result<SysFsGpioInput> {
114 self.gpio.set_direction(GpioDirection::Input)?;
115 Ok(SysFsGpioInput { gpio: self.gpio })
116 }
117}
118
119impl GpioOut for SysFsGpioOutput {
120 type Error = io::Error;
121
122 #[inline]
123 fn set_low(&mut self) -> io::Result<()> {
124 self.gpio.sysfp.write_all(b"0")
125 }
126
127 #[inline]
128 fn set_high(&mut self) -> io::Result<()> {
129 self.gpio.sysfp.write_all(b"1")
130 }
131}
132
133#[derive(Debug)]
135pub struct SysFsGpioInput {
136 gpio: SysFsGpio,
137}
138
139impl SysFsGpioInput {
140 #[inline]
142 pub fn open(gpio_num: u16) -> io::Result<SysFsGpioInput> {
143 Ok(SysFsGpioInput {
144 gpio: SysFsGpio::open(gpio_num, GpioDirection::Input)?,
145 })
146 }
147
148 #[inline]
149 pub fn into_output(mut self) -> io::Result<SysFsGpioOutput> {
150 self.gpio.set_direction(GpioDirection::Output)?;
151 Ok(SysFsGpioOutput { gpio: self.gpio })
152 }
153}
154
155impl GpioIn for SysFsGpioInput {
156 type Error = io::Error;
157
158 #[inline]
159 fn read_value(&mut self) -> Result<GpioValue, Self::Error> {
160 let mut buf: [u8; 1] = [0; 1];
161
162 self.gpio.sysfp.seek(SeekFrom::Start(0))?;
164
165 self.gpio.sysfp.read_exact(&mut buf)?;
167
168 match buf[0] {
169 b'0' => Ok(GpioValue::Low),
170 b'1' => Ok(GpioValue::High),
171 _ => {
172 println!("BUFFER: {:?}", buf);
173 Err(io::Error::new(
174 io::ErrorKind::InvalidData,
175 "read a value that was neither a '0' nor a '1' from Linux sysfs GPIO interface",
176 ))
177 }
178 }
179 }
180}