1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
//! General input/output pins.
//!
//! The [`InputPin`] and [`OutputPin`] traits define pins that can be read and written digitally
//! (i.e. either in a low or high state).
//!
//! There are additionally various `Into*` traits that allow users to re-configure pins to switch
//! between different modes of operation, e.g. [`IntoFloatingInputPin`] turns a pin into an
//! [`InputPin`] that does not employ any pull-up or pull-down resistors.
use core::pin;
use core::task;

pub mod get;
pub mod set;

/// A generic pin that can't be interacted with.
pub trait Pin {
    /// The common error type for all pin operations.
    ///
    /// A single error type for all operations is enforced for simplicity.
    type Error;
}

/// A pin that can be read from.
pub trait InputPin: Pin {
    /// Polls a read operation of this pin to completion.
    fn poll_get(
        self: pin::Pin<&mut Self>,
        cx: &mut task::Context<'_>,
    ) -> task::Poll<Result<bool, Self::Error>>;
}

/// Extension functions for instances of [`InputPin`].
pub trait InputPinExt: InputPin {
    /// Gets the current high or low state of this pin.
    fn get(&mut self) -> get::Get<Self>
    where
        Self: Unpin,
    {
        get::get(self)
    }
}

impl<A> InputPinExt for A where A: InputPin {}

/// A pin that can be written to.
pub trait OutputPin: Pin {
    /// Polls a write operation of this pin to completion.
    fn poll_set(
        self: pin::Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        high: bool,
    ) -> task::Poll<Result<(), Self::Error>>;
}

/// Extension functions for instances of [`OutputPin`].
pub trait OutputPinExt: OutputPin {
    /// Sets the current high or low state of this pin.
    fn set(&mut self, high: bool) -> set::Set<Self>
    where
        Self: Unpin,
    {
        set::set(self, high)
    }
}

impl<A> OutputPinExt for A where A: OutputPin {}

/// A pin that can be turned into an [`InputPin`] that does not employ any pull-up or pull-down
/// resistors.
pub trait IntoFloatingInputPin: Pin {
    /// The type of an [`InputPin`] that does not employ any pull-up or pull-down resistors.
    type FloatingInputPin: InputPin<Error = Self::Error> + Unpin;

    /// Attempts to re-configure this pin into the new mode.
    fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error>;
}

/// A pin that can be turned into an [`InputPin`] that has a pull-up resistor attached.
pub trait IntoPullUpInputPin: Pin {
    /// The type of an [`InputPin`] that has a pull-up resistor attached.
    type PullUpInputPin: InputPin<Error = Self::Error> + Unpin;

    /// Attempts to re-configure this pin into the new mode.
    fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error>;
}

/// A pin that can be turned into an [`InputPin`] that has a pull-down resistor attached.
pub trait IntoPullDownInputPin: Pin {
    /// The type of an [`InputPin`] that has a pull-down resistor attached.
    type PullDownInputPin: InputPin<Error = Self::Error> + Unpin;

    /// Attempts to re-configure this pin into the new mode.
    fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error>;
}

/// A pin that can be turned into an [`OutputPin`] that is in open drain mode.
pub trait IntoOpenDrainOutputPin: Pin {
    /// The type of an [`OutputPin`] that is in open drain mode.
    type OpenDrainOutputPin: OutputPin<Error = Self::Error> + Unpin;

    /// Attempts to re-configure this pin into the new mode.
    fn into_open_drain_output_pin(
        self,
        initial_high: bool,
    ) -> Result<Self::OpenDrainOutputPin, Self::Error>;
}

/// A pin that can be turned into an [`OutputPin`] that is in push-pull mode.
pub trait IntoPushPullOutputPin: Pin {
    /// The type of an [`OutputPin`] that is in push-pull mode.
    type PushPullOutputPin: OutputPin<Error = Self::Error> + Unpin;

    /// Attempts to re-configure this pin into the new mode.
    fn into_push_pull_output_pin(
        self,
        initial_high: bool,
    ) -> Result<Self::PushPullOutputPin, Self::Error>;
}

/// A virtual pin that is not actually connected to a physical pin.
///
/// The pin will always read a fixed value, can be configured to be in any mode, and will always
/// have writes result in no-ops.
#[derive(Clone, Copy, Debug)]
pub struct NoConnect(bool);

impl NoConnect {
    /// Creates a new [`NoConnect`] that will always read the specified high/low value.
    pub fn new(value: bool) -> Self {
        NoConnect(value)
    }
}

impl Pin for NoConnect {
    type Error = futures::never::Never;
}

impl InputPin for NoConnect {
    fn poll_get(
        self: pin::Pin<&mut Self>,
        _cx: &mut task::Context<'_>,
    ) -> task::Poll<Result<bool, Self::Error>> {
        task::Poll::Ready(Ok(false))
    }
}

impl OutputPin for NoConnect {
    fn poll_set(
        self: pin::Pin<&mut Self>,
        _cx: &mut task::Context<'_>,
        _high: bool,
    ) -> task::Poll<Result<(), Self::Error>> {
        task::Poll::Ready(Ok(()))
    }
}

impl IntoFloatingInputPin for NoConnect {
    type FloatingInputPin = Self;

    fn into_floating_input_pin(self) -> Result<Self::FloatingInputPin, Self::Error> {
        Ok(self)
    }
}

impl IntoPullUpInputPin for NoConnect {
    type PullUpInputPin = Self;

    fn into_pull_up_input_pin(self) -> Result<Self::PullUpInputPin, Self::Error> {
        Ok(self)
    }
}

impl IntoPullDownInputPin for NoConnect {
    type PullDownInputPin = Self;

    fn into_pull_down_input_pin(self) -> Result<Self::PullDownInputPin, Self::Error> {
        Ok(self)
    }
}

impl IntoOpenDrainOutputPin for NoConnect {
    type OpenDrainOutputPin = Self;

    fn into_open_drain_output_pin(
        self,
        _initial_high: bool,
    ) -> Result<Self::OpenDrainOutputPin, Self::Error> {
        Ok(self)
    }
}

impl IntoPushPullOutputPin for NoConnect {
    type PushPullOutputPin = Self;

    fn into_push_pull_output_pin(
        self,
        _initial_high: bool,
    ) -> Result<Self::PushPullOutputPin, Self::Error> {
        Ok(self)
    }
}