1#[cfg(feature = "v2_1")]
6use std::ffi::CStr;
7use std::os::unix::prelude::AsRawFd;
8use std::time::Duration;
9
10use super::{
11 Error, OperationType, Result, gpiod,
12 line::{self, Offset, Value, ValueMap},
13 request,
14};
15
16#[derive(Debug, Eq, PartialEq)]
20pub struct Request {
21 pub(crate) request: *mut gpiod::gpiod_line_request,
22}
23
24unsafe impl Send for Request {}
27
28impl Request {
29 pub(crate) unsafe fn from_raw(request: *mut gpiod::gpiod_line_request) -> Result<Self> {
36 Ok(Self { request })
37 }
38
39 #[cfg(feature = "v2_1")]
41 pub fn chip_name(&self) -> Result<&str> {
42 let name = unsafe { gpiod::gpiod_line_request_get_chip_name(self.request) };
45
46 unsafe { CStr::from_ptr(name) }
49 .to_str()
50 .map_err(Error::StringNotUtf8)
51 }
52
53 pub fn num_lines(&self) -> usize {
55 unsafe { gpiod::gpiod_line_request_get_num_requested_lines(self.request) }
57 }
58
59 pub fn offsets(&self) -> Vec<Offset> {
61 let mut offsets = vec![0; self.num_lines()];
62
63 let num_offsets = unsafe {
65 gpiod::gpiod_line_request_get_requested_offsets(
66 self.request,
67 offsets.as_mut_ptr(),
68 self.num_lines(),
69 )
70 };
71 offsets.shrink_to(num_offsets);
72 offsets
73 }
74
75 pub fn value(&self, offset: Offset) -> Result<Value> {
77 let value = unsafe { gpiod::gpiod_line_request_get_value(self.request, offset) };
79
80 if value != 0 && value != 1 {
81 Err(Error::OperationFailed(
82 OperationType::LineRequestGetVal,
83 errno::errno(),
84 ))
85 } else {
86 Value::new(value)
87 }
88 }
89
90 pub fn values_subset(&self, offsets: &[Offset]) -> Result<ValueMap> {
92 let mut values = vec![0; offsets.len()];
93
94 let ret = unsafe {
96 gpiod::gpiod_line_request_get_values_subset(
97 self.request,
98 offsets.len(),
99 offsets.as_ptr(),
100 values.as_mut_ptr(),
101 )
102 };
103
104 if ret == -1 {
105 Err(Error::OperationFailed(
106 OperationType::LineRequestGetValSubset,
107 errno::errno(),
108 ))
109 } else {
110 let mut map = ValueMap::new();
111
112 for (i, val) in values.iter().enumerate() {
113 map.insert(offsets[i], Value::new(*val)?);
114 }
115
116 Ok(map)
117 }
118 }
119
120 pub fn values(&self) -> Result<ValueMap> {
122 self.values_subset(&self.offsets())
123 }
124
125 pub fn set_value(&mut self, offset: Offset, value: Value) -> Result<&mut Self> {
127 let ret =
129 unsafe { gpiod::gpiod_line_request_set_value(self.request, offset, value.value()) };
130
131 if ret == -1 {
132 Err(Error::OperationFailed(
133 OperationType::LineRequestSetVal,
134 errno::errno(),
135 ))
136 } else {
137 Ok(self)
138 }
139 }
140
141 pub fn set_values_subset(&mut self, map: ValueMap) -> Result<&mut Self> {
143 let mut offsets = Vec::new();
144 let mut values = Vec::new();
145
146 for (offset, value) in map {
147 offsets.push(offset);
148 values.push(value.value());
149 }
150
151 let ret = unsafe {
153 gpiod::gpiod_line_request_set_values_subset(
154 self.request,
155 offsets.len(),
156 offsets.as_ptr(),
157 values.as_ptr(),
158 )
159 };
160
161 if ret == -1 {
162 Err(Error::OperationFailed(
163 OperationType::LineRequestSetValSubset,
164 errno::errno(),
165 ))
166 } else {
167 Ok(self)
168 }
169 }
170
171 pub fn set_values(&mut self, values: &[Value]) -> Result<&mut Self> {
173 if values.len() != self.num_lines() {
174 return Err(Error::InvalidArguments);
175 }
176
177 let mut new_values = Vec::new();
178 for value in values {
179 new_values.push(value.value());
180 }
181
182 let ret =
184 unsafe { gpiod::gpiod_line_request_set_values(self.request, new_values.as_ptr()) };
185
186 if ret == -1 {
187 Err(Error::OperationFailed(
188 OperationType::LineRequestSetVal,
189 errno::errno(),
190 ))
191 } else {
192 Ok(self)
193 }
194 }
195
196 pub fn reconfigure_lines(&mut self, lconfig: &line::Config) -> Result<&mut Self> {
198 let ret =
200 unsafe { gpiod::gpiod_line_request_reconfigure_lines(self.request, lconfig.config) };
201
202 if ret == -1 {
203 Err(Error::OperationFailed(
204 OperationType::LineRequestReconfigLines,
205 errno::errno(),
206 ))
207 } else {
208 Ok(self)
209 }
210 }
211
212 pub fn wait_edge_events(&self, timeout: Option<Duration>) -> Result<bool> {
214 let timeout = match timeout {
215 Some(x) => x.as_nanos() as i64,
216 None => -1,
218 };
219
220 let ret = unsafe { gpiod::gpiod_line_request_wait_edge_events(self.request, timeout) };
222
223 match ret {
224 -1 => Err(Error::OperationFailed(
225 OperationType::LineRequestWaitEdgeEvent,
226 errno::errno(),
227 )),
228 0 => Ok(false),
229 _ => Ok(true),
230 }
231 }
232
233 pub fn read_edge_events<'a>(
237 &self,
238 buffer: &'a mut request::Buffer,
239 ) -> Result<request::Events<'a>> {
240 buffer.read_edge_events(self)
241 }
242}
243
244impl AsRawFd for Request {
245 fn as_raw_fd(&self) -> i32 {
247 unsafe { gpiod::gpiod_line_request_get_fd(self.request) }
249 }
250}
251
252impl Drop for Request {
253 fn drop(&mut self) {
255 unsafe { gpiod::gpiod_line_request_release(self.request) }
257 }
258}