3
3
//! [`embedded-hal`]: https://docs.rs/embedded-hal
4
4
5
5
use std:: fmt;
6
+ use std:: marker:: PhantomData ;
6
7
use std:: path:: Path ;
7
8
8
- use embedded_hal:: digital:: InputPin ;
9
+ use embedded_hal:: digital:: { Error , ErrorType , InputPin , OutputPin , PinState , StatefulOutputPin } ;
10
+ use gpiocdev:: {
11
+ line:: { Config , Direction , Offset , Value } ,
12
+ request:: Request ,
13
+ } ;
9
14
#[ cfg( feature = "async-tokio" ) ]
10
15
use gpiocdev:: {
11
16
line:: { EdgeDetection , EdgeKind } ,
12
17
tokio:: AsyncRequest ,
13
18
} ;
14
- use gpiocdev:: {
15
- line:: { Offset , Value } ,
16
- request:: { Config , Request } ,
17
- } ;
19
+
20
+ /// Marker type for a [`CdevPin`] in input mode.
21
+ #[ non_exhaustive]
22
+ pub struct Input ;
23
+
24
+ /// Marker type for a [`CdevPin`] in output mode.
25
+ #[ non_exhaustive]
26
+ pub struct Output ;
18
27
19
28
/// Wrapper around [`gpiocdev::request::Request`] that implements the `embedded-hal` traits.
20
29
#[ derive( Debug ) ]
21
- pub struct CdevPin {
30
+ pub struct CdevPin < MODE > {
22
31
#[ cfg( not( feature = "async-tokio" ) ) ]
23
32
req : Request ,
24
33
#[ cfg( feature = "async-tokio" ) ]
25
34
req : AsyncRequest ,
26
35
line : Offset ,
36
+ line_config : Config ,
37
+ mode : PhantomData < MODE > ,
27
38
}
28
39
29
- impl CdevPin {
30
- /// Creates a new pin for the given `line` on the given `chip`.
40
+ impl CdevPin < Input > {
41
+ /// Creates a new input pin for the given `line` on the given `chip`.
31
42
///
32
43
/// ```
33
44
/// use linux_embedded_hal::CdevPin;
34
45
/// # use linux_embedded_hal::CdevPinError;
35
46
///
36
47
/// # fn main() -> Result<(), CdevPinError> {
37
- /// let mut pin = CdevPin::new("/dev/gpiochip0", 4)?.into_output_pin()?;
48
+ /// let mut pin = CdevPin::new_input("/dev/gpiochip0", 4)?;
49
+ /// pin.is_high()?;
50
+ /// # }
51
+ /// ```
52
+ pub fn new_input < P > ( chip : P , line : u32 ) -> Result < Self , CdevPinError >
53
+ where
54
+ P : AsRef < Path > ,
55
+ {
56
+ let line_config = Config {
57
+ direction : Some ( Direction :: Input ) ,
58
+ ..Default :: default ( )
59
+ } ;
60
+
61
+ let req = Request :: builder ( )
62
+ . on_chip ( chip. as_ref ( ) )
63
+ . from_line_config ( & line_config)
64
+ . request ( ) ?;
65
+
66
+ #[ cfg( feature = "async-tokio" ) ]
67
+ let req = AsyncRequest :: new ( req) ;
68
+
69
+ Ok ( Self {
70
+ req,
71
+ line,
72
+ line_config,
73
+ mode : PhantomData ,
74
+ } )
75
+ }
76
+ }
77
+
78
+ impl CdevPin < Output > {
79
+ /// Creates a new output pin for the given `line` on the given `chip`,
80
+ /// initialized with the given `initial_state`.
81
+ ///
82
+ /// ```
83
+ /// use linux_embedded_hal::CdevPin;
84
+ /// # use linux_embedded_hal::CdevPinError;
85
+ ///
86
+ /// # fn main() -> Result<(), CdevPinError> {
87
+ /// let mut pin = CdevPin::new_output("/dev/gpiochip0", 4)?;
88
+ /// pin.is_set_high()?;
38
89
/// pin.set_high()?;
39
90
/// # }
40
91
/// ```
41
- pub fn new < P > ( chip : P , line : u32 ) -> Result < Self , CdevPinError >
92
+ pub fn new_output < P > ( chip : P , line : u32 , initial_state : PinState ) -> Result < Self , CdevPinError >
42
93
where
43
94
P : AsRef < Path > ,
44
95
{
96
+ let line_config = Config {
97
+ direction : Some ( Direction :: Output ) ,
98
+ active_low : false ,
99
+ value : Some ( match initial_state {
100
+ PinState :: High => Value :: Active ,
101
+ PinState :: Low => Value :: Inactive ,
102
+ } ) ,
103
+ ..Default :: default ( )
104
+ } ;
105
+
45
106
let req = Request :: builder ( )
46
107
. on_chip ( chip. as_ref ( ) )
47
- . with_line ( line )
108
+ . from_line_config ( & line_config )
48
109
. request ( ) ?;
49
110
50
111
#[ cfg( feature = "async-tokio" ) ]
51
112
let req = AsyncRequest :: new ( req) ;
52
113
53
- Ok ( Self { req, line } )
114
+ Ok ( Self {
115
+ req,
116
+ line,
117
+ line_config,
118
+ mode : PhantomData ,
119
+ } )
54
120
}
121
+ }
55
122
123
+ impl < MODE > CdevPin < MODE > {
56
124
#[ inline]
57
125
fn request ( & self ) -> & Request {
58
126
#[ cfg( not( feature = "async-tokio" ) ) ]
@@ -66,58 +134,19 @@ impl CdevPin {
66
134
}
67
135
}
68
136
69
- fn config ( & self ) -> Config {
70
- self . request ( ) . config ( )
71
- }
72
-
73
- /// Set this pin to input mode
74
- pub fn into_input_pin ( self ) -> Result < CdevPin , CdevPinError > {
75
- let config = self . config ( ) ;
76
- let line_config = config. line_config ( self . line ) . unwrap ( ) ;
77
-
78
- if line_config. direction == Some ( gpiocdev:: line:: Direction :: Input ) {
79
- return Ok ( self ) ;
80
- }
81
-
82
- let mut new_config = config;
83
- new_config. as_input ( ) ;
84
- self . request ( ) . reconfigure ( & new_config) ?;
85
-
86
- Ok ( self )
87
- }
88
-
89
- /// Set this pin to output mode
90
- pub fn into_output_pin (
91
- self ,
92
- state : embedded_hal:: digital:: PinState ,
93
- ) -> Result < CdevPin , CdevPinError > {
94
- let config = self . config ( ) ;
95
- let line_config = config. line_config ( self . line ) . unwrap ( ) ;
96
- if line_config. direction == Some ( gpiocdev:: line:: Direction :: Output ) {
97
- return Ok ( self ) ;
98
- }
99
- let is_active_low = line_config. active_low ;
100
-
101
- let mut new_config = config;
102
- new_config. as_output ( state_to_value ( state, is_active_low) ) ;
103
- self . request ( ) . reconfigure ( & new_config) ?;
104
-
105
- Ok ( self )
106
- }
107
- }
108
-
109
- /// Converts a pin state to the gpio_cdev compatible numeric value, accounting
110
- /// for the active_low condition.
111
- fn state_to_value ( state : embedded_hal:: digital:: PinState , is_active_low : bool ) -> Value {
112
- if is_active_low {
113
- match state {
114
- embedded_hal:: digital:: PinState :: High => Value :: Inactive ,
115
- embedded_hal:: digital:: PinState :: Low => Value :: Active ,
116
- }
117
- } else {
118
- match state {
119
- embedded_hal:: digital:: PinState :: High => Value :: Active ,
120
- embedded_hal:: digital:: PinState :: Low => Value :: Inactive ,
137
+ /// Converts a pin state to a value, depending on
138
+ /// whether the pin is configured as active-low.
139
+ fn state_to_value ( & self , state : PinState ) -> Value {
140
+ if self . line_config . active_low {
141
+ match state {
142
+ PinState :: High => Value :: Inactive ,
143
+ PinState :: Low => Value :: Active ,
144
+ }
145
+ } else {
146
+ match state {
147
+ PinState :: High => Value :: Active ,
148
+ PinState :: Low => Value :: Inactive ,
149
+ }
121
150
}
122
151
}
123
152
}
@@ -146,60 +175,65 @@ impl std::error::Error for CdevPinError {
146
175
}
147
176
}
148
177
149
- impl embedded_hal :: digital :: Error for CdevPinError {
178
+ impl Error for CdevPinError {
150
179
fn kind ( & self ) -> embedded_hal:: digital:: ErrorKind {
151
180
use embedded_hal:: digital:: ErrorKind ;
152
181
ErrorKind :: Other
153
182
}
154
183
}
155
184
156
- impl embedded_hal :: digital :: ErrorType for CdevPin {
185
+ impl < MODE > ErrorType for CdevPin < MODE > {
157
186
type Error = CdevPinError ;
158
187
}
159
188
160
- impl embedded_hal:: digital:: OutputPin for CdevPin {
189
+ impl InputPin for CdevPin < Input > {
190
+ fn is_low ( & mut self ) -> Result < bool , Self :: Error > {
191
+ let low_value = self . state_to_value ( PinState :: Low ) ;
192
+ Ok ( self . request ( ) . value ( self . line ) ? == low_value)
193
+ }
194
+
195
+ fn is_high ( & mut self ) -> Result < bool , Self :: Error > {
196
+ let high_value = self . state_to_value ( PinState :: High ) ;
197
+ Ok ( self . request ( ) . value ( self . line ) ? == high_value)
198
+ }
199
+ }
200
+
201
+ impl OutputPin for CdevPin < Output > {
161
202
fn set_low ( & mut self ) -> Result < ( ) , Self :: Error > {
162
- let line = self . line ;
163
- let is_active_low = self . config ( ) . line_config ( line) . unwrap ( ) . active_low ;
164
- self . request ( )
165
- . set_value (
166
- line,
167
- state_to_value ( embedded_hal:: digital:: PinState :: Low , is_active_low) ,
168
- )
169
- . map ( |_| ( ) )
170
- . map_err ( CdevPinError :: from)
203
+ let new_value = self . state_to_value ( PinState :: Low ) ;
204
+
205
+ self . request ( ) . set_value ( self . line , new_value) ?;
206
+ self . line_config . value = Some ( new_value) ;
207
+
208
+ Ok ( ( ) )
171
209
}
172
210
173
211
fn set_high ( & mut self ) -> Result < ( ) , Self :: Error > {
174
- let line = self . line ;
175
- let is_active_low = self . config ( ) . line_config ( line) . unwrap ( ) . active_low ;
176
- self . request ( )
177
- . set_value (
178
- line,
179
- state_to_value ( embedded_hal:: digital:: PinState :: High , is_active_low) ,
180
- )
181
- . map ( |_| ( ) )
182
- . map_err ( CdevPinError :: from)
212
+ let new_value = self . state_to_value ( PinState :: High ) ;
213
+
214
+ self . request ( ) . set_value ( self . line , new_value) ?;
215
+ self . line_config . value = Some ( new_value) ;
216
+
217
+ Ok ( ( ) )
183
218
}
184
219
}
185
220
186
- impl InputPin for CdevPin {
187
- fn is_high ( & mut self ) -> Result < bool , Self :: Error > {
188
- let line = self . line ;
189
- let is_active_low = self . config ( ) . line_config ( line) . unwrap ( ) . active_low ;
190
- self . request ( )
191
- . value ( line)
192
- . map ( |val| val == state_to_value ( embedded_hal:: digital:: PinState :: High , is_active_low) )
193
- . map_err ( CdevPinError :: from)
221
+ impl StatefulOutputPin for CdevPin < Output > {
222
+ #[ inline]
223
+ fn is_set_low ( & mut self ) -> Result < bool , Self :: Error > {
224
+ let low_value = self . state_to_value ( PinState :: Low ) ;
225
+ Ok ( self . line_config . value == Some ( low_value) )
194
226
}
195
227
196
- fn is_low ( & mut self ) -> Result < bool , Self :: Error > {
197
- self . is_high ( ) . map ( |val| !val)
228
+ #[ inline]
229
+ fn is_set_high ( & mut self ) -> Result < bool , Self :: Error > {
230
+ let high_value = self . state_to_value ( PinState :: High ) ;
231
+ Ok ( self . line_config . value == Some ( high_value) )
198
232
}
199
233
}
200
234
201
235
#[ cfg( feature = "async-tokio" ) ]
202
- impl embedded_hal_async:: digital:: Wait for CdevPin {
236
+ impl embedded_hal_async:: digital:: Wait for CdevPin < Input > {
203
237
async fn wait_for_high ( & mut self ) -> Result < ( ) , Self :: Error > {
204
238
if self . is_high ( ) ? {
205
239
return Ok ( ( ) ) ;
@@ -217,15 +251,14 @@ impl embedded_hal_async::digital::Wait for CdevPin {
217
251
}
218
252
219
253
async fn wait_for_rising_edge ( & mut self ) -> Result < ( ) , Self :: Error > {
220
- let config = self . config ( ) ;
221
- let line_config = config. line_config ( self . line ) . unwrap ( ) ;
222
254
if !matches ! (
223
- line_config. edge_detection,
255
+ self . line_config. edge_detection,
224
256
Some ( EdgeDetection :: RisingEdge | EdgeDetection :: BothEdges )
225
257
) {
226
- let mut new_config = config;
258
+ let mut new_config = self . req . as_ref ( ) . config ( ) ;
227
259
new_config. with_edge_detection ( EdgeDetection :: RisingEdge ) ;
228
- self . request ( ) . reconfigure ( & new_config) ?;
260
+ self . req . as_ref ( ) . reconfigure ( & new_config) ?;
261
+ self . line_config . edge_detection = Some ( EdgeDetection :: RisingEdge ) ;
229
262
}
230
263
231
264
loop {
@@ -237,15 +270,14 @@ impl embedded_hal_async::digital::Wait for CdevPin {
237
270
}
238
271
239
272
async fn wait_for_falling_edge ( & mut self ) -> Result < ( ) , Self :: Error > {
240
- let config = self . config ( ) ;
241
- let line_config = config. line_config ( self . line ) . unwrap ( ) ;
242
273
if !matches ! (
243
- line_config. edge_detection,
274
+ self . line_config. edge_detection,
244
275
Some ( EdgeDetection :: FallingEdge | EdgeDetection :: BothEdges )
245
276
) {
246
- let mut new_config = config;
277
+ let mut new_config = self . req . as_ref ( ) . config ( ) ;
247
278
new_config. with_edge_detection ( EdgeDetection :: FallingEdge ) ;
248
- self . request ( ) . reconfigure ( & new_config) ?;
279
+ self . req . as_ref ( ) . reconfigure ( & new_config) ?;
280
+ self . line_config . edge_detection = Some ( EdgeDetection :: FallingEdge ) ;
249
281
}
250
282
251
283
loop {
@@ -257,12 +289,14 @@ impl embedded_hal_async::digital::Wait for CdevPin {
257
289
}
258
290
259
291
async fn wait_for_any_edge ( & mut self ) -> Result < ( ) , Self :: Error > {
260
- let config = self . config ( ) ;
261
- let line_config = config. line_config ( self . line ) . unwrap ( ) ;
262
- if line_config. edge_detection != Some ( EdgeDetection :: BothEdges ) {
263
- let mut new_config = config;
292
+ if !matches ! (
293
+ self . line_config. edge_detection,
294
+ Some ( EdgeDetection :: BothEdges )
295
+ ) {
296
+ let mut new_config = self . req . as_ref ( ) . config ( ) ;
264
297
new_config. with_edge_detection ( EdgeDetection :: BothEdges ) ;
265
- self . request ( ) . reconfigure ( & new_config) ?;
298
+ self . req . as_ref ( ) . reconfigure ( & new_config) ?;
299
+ self . line_config . edge_detection = Some ( EdgeDetection :: BothEdges ) ;
266
300
}
267
301
268
302
self . req . read_edge_event ( ) . await ?;
0 commit comments