|
| 1 | +//! General input/output pins. |
| 2 | +//! |
| 3 | +//! The [`InputPin`] and [`OutputPin`] traits define pins that can be read and written digitally |
| 4 | +//! (i.e. either in a low or high state). |
| 5 | +//! |
| 6 | +//! There are additionally various `Into*` traits that allow users to re-configure pins to switch |
| 7 | +//! between different modes of operation, e.g. [`IntoFloatingInputPin`] turns a pin into an |
| 8 | +//! [`InputPin`] that does not employ any pull-up or pull-down resistors. |
| 9 | +use core::pin; |
| 10 | +use core::task; |
| 11 | + |
| 12 | +pub mod get; |
| 13 | +pub mod set; |
| 14 | + |
| 15 | +/// A generic pin that can't be interacted with. |
| 16 | +pub trait Pin { |
| 17 | + /// The common error type for all pin operations. |
| 18 | + /// |
| 19 | + /// A single error type for all operations is enforced for simplicity. |
| 20 | + type Error; |
| 21 | +} |
| 22 | + |
| 23 | +/// A pin that can be read from. |
| 24 | +pub trait InputPin: Pin { |
| 25 | + /// Polls a read operation of this pin to completion. |
| 26 | + fn poll_get( |
| 27 | + self: pin::Pin<&mut Self>, |
| 28 | + cx: &mut task::Context<'_>, |
| 29 | + ) -> task::Poll<Result<bool, Self::Error>>; |
| 30 | +} |
| 31 | + |
| 32 | +/// Extension functions for instances of [`InputPin`]. |
| 33 | +pub trait InputPinExt: InputPin { |
| 34 | + /// Gets the current high or low state of this pin. |
| 35 | + fn get(&mut self) -> get::Get<Self> |
| 36 | + where |
| 37 | + Self: Unpin, |
| 38 | + { |
| 39 | + get::get(self) |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +impl<A> InputPinExt for A where A: InputPin {} |
| 44 | + |
| 45 | +/// A pin that can be written to. |
| 46 | +pub trait OutputPin: Pin { |
| 47 | + /// Polls a write operation of this pin to completion. |
| 48 | + fn poll_set( |
| 49 | + self: pin::Pin<&mut Self>, |
| 50 | + cx: &mut task::Context<'_>, |
| 51 | + high: bool, |
| 52 | + ) -> task::Poll<Result<(), Self::Error>>; |
| 53 | +} |
| 54 | + |
| 55 | +/// Extension functions for instances of [`OutputPin`]. |
| 56 | +pub trait OutputPinExt: OutputPin { |
| 57 | + /// Sets the current high or low state of this pin. |
| 58 | + fn set(&mut self, high: bool) -> set::Set<Self> |
| 59 | + where |
| 60 | + Self: Unpin, |
| 61 | + { |
| 62 | + set::set(self, high) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +impl<A> OutputPinExt for A where A: OutputPin {} |
| 67 | + |
| 68 | +/// A pin that can be turned into an [`InputPin`] that does not employ any pull-up or pull-down |
| 69 | +/// resistors. |
| 70 | +pub trait IntoFloatingInputPin: Pin { |
| 71 | + /// The type of an [`InputPin`] that does not employ any pull-up or pull-down resistors. |
| 72 | + type FloatingInputPin: InputPin<Error = Self::Error> + Unpin; |
| 73 | + |
| 74 | + /// Attempts to re-configure this pin into the new mode. |
| 75 | + fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error>; |
| 76 | +} |
| 77 | + |
| 78 | +/// A pin that can be turned into an [`InputPin`] that has a pull-up resistor attached. |
| 79 | +pub trait IntoPullUpInputPin: Pin { |
| 80 | + /// The type of an [`InputPin`] that has a pull-up resistor attached. |
| 81 | + type PullUpInputPin: InputPin<Error = Self::Error> + Unpin; |
| 82 | + |
| 83 | + /// Attempts to re-configure this pin into the new mode. |
| 84 | + fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error>; |
| 85 | +} |
| 86 | + |
| 87 | +/// A pin that can be turned into an [`InputPin`] that has a pull-down resistor attached. |
| 88 | +pub trait IntoPullDownInputPin: Pin { |
| 89 | + /// The type of an [`InputPin`] that has a pull-down resistor attached. |
| 90 | + type PullDownInputPin: InputPin<Error = Self::Error> + Unpin; |
| 91 | + |
| 92 | + /// Attempts to re-configure this pin into the new mode. |
| 93 | + fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error>; |
| 94 | +} |
| 95 | + |
| 96 | +/// A pin that can be turned into an [`OutputPin`] that is in open drain mode. |
| 97 | +pub trait IntoOpenDrainOutputPin: Pin { |
| 98 | + /// The type of an [`OutputPin`] that is in open drain mode. |
| 99 | + type OpenDrainOutputPin: OutputPin<Error = Self::Error> + Unpin; |
| 100 | + |
| 101 | + /// Attempts to re-configure this pin into the new mode. |
| 102 | + fn into_open_drain_output_pin( |
| 103 | + self, |
| 104 | + initial_high: bool, |
| 105 | + ) -> Result<Self::OpenDrainOutputPin, Self::Error>; |
| 106 | +} |
| 107 | + |
| 108 | +/// A pin that can be turned into an [`OutputPin`] that is in push-pull mode. |
| 109 | +pub trait IntoPushPullOutputPin: Pin { |
| 110 | + /// The type of an [`OutputPin`] that is in push-pull mode. |
| 111 | + type PushPullOutputPin: OutputPin<Error = Self::Error> + Unpin; |
| 112 | + |
| 113 | + /// Attempts to re-configure this pin into the new mode. |
| 114 | + fn into_push_pull_output_pin( |
| 115 | + self, |
| 116 | + initial_high: bool, |
| 117 | + ) -> Result<Self::PushPullOutputPin, Self::Error>; |
| 118 | +} |
| 119 | + |
| 120 | +/// A virtual pin that is not actually connected to a physical pin. |
| 121 | +/// |
| 122 | +/// The pin will always read a fixed value, can be configured to be in any mode, and will always |
| 123 | +/// have writes result in no-ops. |
| 124 | +#[derive(Clone, Copy, Debug)] |
| 125 | +pub struct NoConnect(bool); |
| 126 | + |
| 127 | +impl NoConnect { |
| 128 | + /// Creates a new [`NoConnect`] that will always read the specified high/low value. |
| 129 | + pub fn new(value: bool) -> Self { |
| 130 | + NoConnect(value) |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +impl Pin for NoConnect { |
| 135 | + type Error = futures::never::Never; |
| 136 | +} |
| 137 | + |
| 138 | +impl InputPin for NoConnect { |
| 139 | + fn poll_get( |
| 140 | + self: pin::Pin<&mut Self>, |
| 141 | + _cx: &mut task::Context<'_>, |
| 142 | + ) -> task::Poll<Result<bool, Self::Error>> { |
| 143 | + task::Poll::Ready(Ok(false)) |
| 144 | + } |
| 145 | +} |
| 146 | + |
| 147 | +impl OutputPin for NoConnect { |
| 148 | + fn poll_set( |
| 149 | + self: pin::Pin<&mut Self>, |
| 150 | + _cx: &mut task::Context<'_>, |
| 151 | + _high: bool, |
| 152 | + ) -> task::Poll<Result<(), Self::Error>> { |
| 153 | + task::Poll::Ready(Ok(())) |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +impl IntoFloatingInputPin for NoConnect { |
| 158 | + type FloatingInputPin = Self; |
| 159 | + |
| 160 | + fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error> { |
| 161 | + Ok(self) |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +impl IntoPullUpInputPin for NoConnect { |
| 166 | + type PullUpInputPin = Self; |
| 167 | + |
| 168 | + fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error> { |
| 169 | + Ok(self) |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +impl IntoPullDownInputPin for NoConnect { |
| 174 | + type PullDownInputPin = Self; |
| 175 | + |
| 176 | + fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error> { |
| 177 | + Ok(self) |
| 178 | + } |
| 179 | +} |
| 180 | + |
| 181 | +impl IntoOpenDrainOutputPin for NoConnect { |
| 182 | + type OpenDrainOutputPin = Self; |
| 183 | + |
| 184 | + fn into_open_drain_output_pin( |
| 185 | + self, |
| 186 | + _initial_high: bool, |
| 187 | + ) -> Result<Self::OpenDrainOutputPin, Self::Error> { |
| 188 | + Ok(self) |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +impl IntoPushPullOutputPin for NoConnect { |
| 193 | + type PushPullOutputPin = Self; |
| 194 | + |
| 195 | + fn into_push_pull_output_pin( |
| 196 | + self, |
| 197 | + _initial_high: bool, |
| 198 | + ) -> Result<Self::PushPullOutputPin, Self::Error> { |
| 199 | + Ok(self) |
| 200 | + } |
| 201 | +} |
0 commit comments