embedded_platform/
gpio.rs

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.
9use core::pin;
10use core::task;
11
12pub mod get;
13pub mod set;
14
15/// A generic pin that can't be interacted with.
16pub 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.
24pub 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`].
33pub 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
43impl<A> InputPinExt for A where A: InputPin {}
44
45/// A pin that can be written to.
46pub 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`].
56pub 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
66impl<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.
70pub 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.
79pub 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.
88pub 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.
97pub 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.
109pub 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)]
125pub struct NoConnect(bool);
126
127impl 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
134impl Pin for NoConnect {
135    type Error = futures::never::Never;
136}
137
138impl 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
147impl 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
157impl 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
165impl 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
173impl 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
181impl 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
192impl 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}