chip_select/
lib.rs

1//! Chip-Select GPIO support traits.
2
3#![no_std]
4#![forbid(unsafe_code)]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6
7#[cfg(all(feature = "hal-0_2", feature = "hal-1_0"))]
8compile_error!(
9    "HAL feature \"hal-0_2\" and feature \"hal-1_0\" cannot be enabled at the same time"
10);
11
12#[cfg(not(any(feature = "hal-0_2", feature = "hal-1_0")))]
13compile_error!("A HAL feature (\"hal-0_2\" or \"hal-1_0\") must be enabled");
14
15#[cfg(feature = "hal-0_2")]
16#[cfg_attr(docsrs, doc(cfg(feature = "hal-0_2")))]
17use hal_0_2::digital::v2::OutputPin;
18
19#[cfg(feature = "hal-1_0")]
20#[cfg_attr(docsrs, doc(cfg(feature = "hal-1_0")))]
21use hal_1_0::digital::OutputPin;
22
23/// A chip-select trait.
24pub trait ChipSelect {
25    /// Selects the chip, driving the line low.
26    fn select(&mut self);
27
28    /// Deselects the chip, driving the line high.
29    fn deselect(&mut self);
30}
31
32/// A chip-select trait.
33pub trait ChipSelectGuarded: ChipSelect {
34    /// A guard that, when dropped, deselects the chip.
35    type Guard<'a>
36    where
37        Self: 'a;
38
39    /// Selects the device and returns a guard that, when dropped, deselects the chip.
40    fn select_guard(&mut self) -> Self::Guard<'_>;
41}
42
43/// Marker trait to indicate that a pin is active low.
44pub trait ActiveLow {}
45
46/// Marker trait to indicate that a pin is active high.
47pub trait ActiveHigh {}
48
49/// A chip select pin with active-low behavior.
50pub struct ChipSelectActiveLow<Pin>(Pin);
51
52/// A chip select pin with active-high behavior.
53pub struct ChipSelectActiveHigh<Pin>(Pin);
54
55impl<Pin> ChipSelectActiveLow<Pin>
56where
57    Pin: OutputPin,
58{
59    /// Initialize the chip select.
60    pub const fn new(pin: Pin) -> Self {
61        Self(pin)
62    }
63
64    /// Selects the chip, driving the line low.
65    pub fn select(&mut self) {
66        <Pin as OutputPin>::set_low(&mut self.0).ok();
67    }
68
69    /// Deselects the chip, driving the line high.
70    pub fn deselect(&mut self) {
71        <Pin as OutputPin>::set_high(&mut self.0).ok();
72    }
73
74    /// Consumes self and returns the wrapped pin.
75    #[must_use]
76    pub fn into_inner(self) -> Pin {
77        self.0
78    }
79
80    /// Selects the device and returns a guard that, when dropped, deselects the chip.
81    #[must_use]
82    pub fn select_guard(&mut self) -> DeselectOnDrop<Self> {
83        self.select();
84        DeselectOnDrop::from(self)
85    }
86}
87
88impl<Pin> ChipSelectActiveHigh<Pin>
89where
90    Pin: OutputPin,
91{
92    /// Initialize the chip select.
93    pub const fn new(pin: Pin) -> Self {
94        Self(pin)
95    }
96
97    /// Selects the chip, driving the line high.
98    pub fn select(&mut self) {
99        <Pin as OutputPin>::set_high(&mut self.0).ok();
100    }
101
102    /// Deselects the chip, driving the line low.
103    pub fn deselect(&mut self) {
104        <Pin as OutputPin>::set_low(&mut self.0).ok();
105    }
106
107    /// Consumes self and returns the wrapped pin.
108    #[must_use]
109    pub fn into_inner(self) -> Pin {
110        self.0
111    }
112
113    /// Selects the device and returns a guard that, when dropped, deselects the chip.
114    #[must_use]
115    pub fn select_guard(&mut self) -> DeselectOnDrop<Self> {
116        self.select();
117        DeselectOnDrop::from(self)
118    }
119}
120
121impl<Pin> From<Pin> for ChipSelectActiveLow<Pin>
122where
123    Pin: OutputPin,
124{
125    fn from(value: Pin) -> Self {
126        Self::new(value)
127    }
128}
129
130impl<Pin> From<Pin> for ChipSelectActiveHigh<Pin>
131where
132    Pin: OutputPin,
133{
134    fn from(value: Pin) -> Self {
135        Self::new(value)
136    }
137}
138
139impl<Pin> ActiveLow for ChipSelectActiveLow<Pin> where Pin: OutputPin {}
140
141impl<Pin> ActiveHigh for ChipSelectActiveHigh<Pin> where Pin: OutputPin {}
142
143impl<Pin> ChipSelect for ChipSelectActiveLow<Pin>
144where
145    Pin: OutputPin,
146{
147    fn select(&mut self) {
148        self.select()
149    }
150
151    fn deselect(&mut self) {
152        self.deselect()
153    }
154}
155
156impl<Pin> ChipSelectGuarded for ChipSelectActiveLow<Pin>
157where
158    Pin: OutputPin,
159{
160    type Guard<'a> = DeselectOnDrop<'a, Self> where Pin: 'a;
161
162    /// Selects the device and returns a guard that, when dropped, deselects the chip.
163    fn select_guard(&mut self) -> DeselectOnDrop<Self> {
164        self.select_guard()
165    }
166}
167
168impl<Pin> ChipSelect for ChipSelectActiveHigh<Pin>
169where
170    Pin: OutputPin,
171{
172    fn select(&mut self) {
173        self.select()
174    }
175
176    fn deselect(&mut self) {
177        self.deselect()
178    }
179}
180
181impl<Pin> ChipSelectGuarded for ChipSelectActiveHigh<Pin>
182where
183    Pin: OutputPin,
184{
185    type Guard<'a> = DeselectOnDrop<'a, Self> where Pin: 'a;
186
187    /// Selects the device and returns a guard that, when dropped, deselects the chip.
188    fn select_guard(&mut self) -> Self::Guard<'_> {
189        self.select_guard()
190    }
191}
192
193/// A guard that deselects the chip when it is dropped.
194pub struct DeselectOnDrop<'a, T>(&'a mut T)
195where
196    T: ChipSelect;
197
198impl<'a, T> From<&'a mut T> for DeselectOnDrop<'a, T>
199where
200    T: ChipSelect,
201{
202    fn from(value: &'a mut T) -> Self {
203        Self(value)
204    }
205}
206
207impl<'a, T> Drop for DeselectOnDrop<'a, T>
208where
209    T: ChipSelect,
210{
211    fn drop(&mut self) {
212        self.0.deselect()
213    }
214}