|
5 | 5 | /// Newtype around [`gpio_cdev::LineHandle`] that implements the `embedded-hal` traits
|
6 | 6 | ///
|
7 | 7 | /// [`gpio_cdev::LineHandle`]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.LineHandle.html
|
8 |
| -pub struct CdevPin(pub gpio_cdev::LineHandle, bool); |
| 8 | +pub struct CdevPin(pub gpio_cdev::LineHandle, gpio_cdev::LineInfo); |
9 | 9 |
|
10 | 10 | impl CdevPin {
|
11 | 11 | /// See [`gpio_cdev::Line::request`][0] for details.
|
12 | 12 | ///
|
13 | 13 | /// [0]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.Line.html#method.request
|
14 | 14 | pub fn new(handle: gpio_cdev::LineHandle) -> Result<Self, gpio_cdev::errors::Error> {
|
15 | 15 | let info = handle.line().info()?;
|
16 |
| - Ok(CdevPin(handle, info.is_active_low())) |
| 16 | + Ok(CdevPin(handle, info)) |
| 17 | + } |
| 18 | + |
| 19 | + fn get_input_flags(&self) -> gpio_cdev::LineRequestFlags { |
| 20 | + if self.1.is_active_low() { |
| 21 | + return gpio_cdev::LineRequestFlags::INPUT | gpio_cdev::LineRequestFlags::ACTIVE_LOW; |
| 22 | + } |
| 23 | + gpio_cdev::LineRequestFlags::INPUT |
| 24 | + } |
| 25 | + |
| 26 | + fn get_output_flags(&self) -> gpio_cdev::LineRequestFlags { |
| 27 | + let mut flags = gpio_cdev::LineRequestFlags::OUTPUT; |
| 28 | + if self.1.is_active_low() { |
| 29 | + flags.insert(gpio_cdev::LineRequestFlags::ACTIVE_LOW); |
| 30 | + } |
| 31 | + if self.1.is_open_drain() { |
| 32 | + flags.insert(gpio_cdev::LineRequestFlags::OPEN_DRAIN); |
| 33 | + } else if self.1.is_open_source() { |
| 34 | + flags.insert(gpio_cdev::LineRequestFlags::OPEN_SOURCE); |
| 35 | + } |
| 36 | + return flags; |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +/// Converts a pin state to the gpio_cdev compatible numeric value, accounting |
| 41 | +/// for the active_low condition. |
| 42 | +fn state_to_value(state: embedded_hal::digital::PinState, is_active_low: bool) -> u8 { |
| 43 | + if is_active_low { |
| 44 | + match state { |
| 45 | + embedded_hal::digital::PinState::High => 0, |
| 46 | + embedded_hal::digital::PinState::Low => 1, |
| 47 | + } |
| 48 | + } else { |
| 49 | + match state { |
| 50 | + embedded_hal::digital::PinState::High => 1, |
| 51 | + embedded_hal::digital::PinState::Low => 0, |
| 52 | + } |
17 | 53 | }
|
18 | 54 | }
|
19 | 55 |
|
20 | 56 | impl embedded_hal::digital::blocking::OutputPin for CdevPin {
|
21 | 57 | type Error = gpio_cdev::errors::Error;
|
22 | 58 |
|
23 | 59 | fn set_low(&mut self) -> Result<(), Self::Error> {
|
24 |
| - if self.1 { |
25 |
| - self.0.set_value(1) |
26 |
| - } else { |
27 |
| - self.0.set_value(0) |
28 |
| - } |
| 60 | + self.0.set_value(state_to_value( |
| 61 | + embedded_hal::digital::PinState::Low, |
| 62 | + self.1.is_active_low(), |
| 63 | + )) |
29 | 64 | }
|
30 | 65 |
|
31 | 66 | fn set_high(&mut self) -> Result<(), Self::Error> {
|
32 |
| - if self.1 { |
33 |
| - self.0.set_value(0) |
34 |
| - } else { |
35 |
| - self.0.set_value(1) |
36 |
| - } |
| 67 | + self.0.set_value(state_to_value( |
| 68 | + embedded_hal::digital::PinState::High, |
| 69 | + self.1.is_active_low(), |
| 70 | + )) |
37 | 71 | }
|
38 | 72 | }
|
39 | 73 |
|
40 | 74 | impl embedded_hal::digital::blocking::InputPin for CdevPin {
|
41 | 75 | type Error = gpio_cdev::errors::Error;
|
42 | 76 |
|
43 | 77 | fn is_high(&self) -> Result<bool, Self::Error> {
|
44 |
| - if !self.1 { |
45 |
| - self.0.get_value().map(|val| val != 0) |
46 |
| - } else { |
47 |
| - self.0.get_value().map(|val| val == 0) |
48 |
| - } |
| 78 | + self.0.get_value().map(|val| { |
| 79 | + val == state_to_value( |
| 80 | + embedded_hal::digital::PinState::High, |
| 81 | + self.1.is_active_low(), |
| 82 | + ) |
| 83 | + }) |
49 | 84 | }
|
50 | 85 |
|
51 | 86 | fn is_low(&self) -> Result<bool, Self::Error> {
|
52 | 87 | self.is_high().map(|val| !val)
|
53 | 88 | }
|
54 | 89 | }
|
55 | 90 |
|
| 91 | +impl embedded_hal::digital::blocking::IoPin<CdevPin, CdevPin> for CdevPin { |
| 92 | + type Error = gpio_cdev::errors::Error; |
| 93 | + |
| 94 | + fn into_input_pin(self) -> Result<CdevPin, Self::Error> { |
| 95 | + if self.1.direction() == gpio_cdev::LineDirection::In { |
| 96 | + return Ok(self); |
| 97 | + } |
| 98 | + let line = self.0.line().clone(); |
| 99 | + let input_flags = self.get_input_flags(); |
| 100 | + let consumer = self.1.consumer().unwrap_or("").to_owned(); |
| 101 | + |
| 102 | + // Drop self to free the line before re-requesting it in a new mode. |
| 103 | + std::mem::drop(self); |
| 104 | + |
| 105 | + CdevPin::new(line.request(input_flags, 0, &consumer)?) |
| 106 | + } |
| 107 | + |
| 108 | + fn into_output_pin( |
| 109 | + self, |
| 110 | + state: embedded_hal::digital::PinState, |
| 111 | + ) -> Result<CdevPin, Self::Error> { |
| 112 | + if self.1.direction() == gpio_cdev::LineDirection::Out { |
| 113 | + return Ok(self); |
| 114 | + } |
| 115 | + |
| 116 | + let line = self.0.line().clone(); |
| 117 | + let output_flags = self.get_output_flags(); |
| 118 | + let consumer = self.1.consumer().unwrap_or("").to_owned(); |
| 119 | + |
| 120 | + // Drop self to free the line before re-requesting it in a new mode. |
| 121 | + std::mem::drop(self); |
| 122 | + |
| 123 | + CdevPin::new(line.request( |
| 124 | + output_flags, |
| 125 | + state_to_value( |
| 126 | + state, |
| 127 | + output_flags.intersects(gpio_cdev::LineRequestFlags::ACTIVE_LOW), |
| 128 | + ), |
| 129 | + &consumer, |
| 130 | + )?) |
| 131 | + } |
| 132 | +} |
| 133 | + |
56 | 134 | impl core::ops::Deref for CdevPin {
|
57 | 135 | type Target = gpio_cdev::LineHandle;
|
58 | 136 |
|
|
0 commit comments