libgpiod/line_info.rs
1// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2022 Linaro Ltd.
3// SPDX-FileCopyrightText: 2022 Viresh Kumar <viresh.kumar@linaro.org>
4
5use std::ops::Deref;
6use std::str;
7use std::time::Duration;
8use std::{ffi::CStr, marker::PhantomData};
9
10use super::{
11 Error, Result, gpiod,
12 line::{Bias, Direction, Drive, Edge, EventClock, Offset},
13};
14
15/// Line info reference
16///
17/// Exposes functions for retrieving kernel information about both requested and
18/// free lines. Line info object contains an immutable snapshot of a line's status.
19///
20/// The line info contains all the publicly available information about a
21/// line, which does not include the line value. The line must be requested
22/// to access the line value.
23///
24/// [InfoRef] only abstracts a reference to a [gpiod::gpiod_line_info] instance whose lifetime is managed
25/// by a different object instance. The owned counter-part of this type is [Info].
26#[derive(Debug)]
27#[repr(transparent)]
28pub struct InfoRef {
29 _info: gpiod::gpiod_line_info,
30 // Avoid the automatic `Sync` implementation.
31 //
32 // The C lib does not allow parallel invocations of the API. We could model
33 // that by restricting all wrapper functions to `&mut Info` - which would
34 // ensure exclusive access. But that would make the API a bit weird...
35 // So instead we just suppress the `Sync` implementation, which suppresses
36 // the `Send` implementation on `&Info` - disallowing to send it to other
37 // threads, making concurrent use impossible.
38 _not_sync: PhantomData<*mut gpiod::gpiod_line_info>,
39}
40
41impl InfoRef {
42 /// Converts a non-owning pointer to a wrapper reference of a specific
43 /// lifetime
44 ///
45 /// No ownership will be assumed, the pointer must be free'd by the original
46 /// owner.
47 ///
48 /// SAFETY: The pointer must point to an instance that is valid for the
49 /// entire lifetime 'a. The instance must be owned by an object that is
50 /// owned by the thread invoking this method. The owning object may not be
51 /// moved to another thread for the entire lifetime 'a.
52 pub(crate) unsafe fn from_raw<'a>(info: *mut gpiod::gpiod_line_info) -> &'a InfoRef {
53 unsafe { &*(info as *mut _) }
54 }
55
56 fn as_raw_ptr(&self) -> *mut gpiod::gpiod_line_info {
57 self as *const _ as *mut _
58 }
59
60 /// Clones the line info object.
61 pub fn try_clone(&self) -> Result<Info> {
62 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
63 let copy = unsafe { gpiod::gpiod_line_info_copy(self.as_raw_ptr()) };
64 if copy.is_null() {
65 return Err(Error::OperationFailed(
66 crate::OperationType::LineInfoCopy,
67 errno::errno(),
68 ));
69 }
70
71 // SAFETY: The copy succeeded, we are the owner and stop using the
72 // pointer after this.
73 Ok(unsafe { Info::from_raw(copy) })
74 }
75
76 /// Get the offset of the line within the GPIO chip.
77 ///
78 /// The offset uniquely identifies the line on the chip. The combination of the chip and offset
79 /// uniquely identifies the line within the system.
80 pub fn offset(&self) -> Offset {
81 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
82 unsafe { gpiod::gpiod_line_info_get_offset(self.as_raw_ptr()) }
83 }
84
85 /// Get GPIO line's name.
86 pub fn name(&self) -> Result<&str> {
87 // SAFETY: The string returned by libgpiod is guaranteed to live as long
88 // as the `struct Info`.
89 let name = unsafe { gpiod::gpiod_line_info_get_name(self.as_raw_ptr()) };
90 if name.is_null() {
91 return Err(Error::NullString("GPIO line's name"));
92 }
93
94 // SAFETY: The string is guaranteed to be valid here by the C API.
95 unsafe { CStr::from_ptr(name) }
96 .to_str()
97 .map_err(Error::StringNotUtf8)
98 }
99
100 /// Returns True if the line is in use, false otherwise.
101 ///
102 /// The user space can't know exactly why a line is busy. It may have been
103 /// requested by another process or hogged by the kernel. It only matters that
104 /// the line is used and we can't request it.
105 pub fn is_used(&self) -> bool {
106 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
107 unsafe { gpiod::gpiod_line_info_is_used(self.as_raw_ptr()) }
108 }
109
110 /// Get the GPIO line's consumer name.
111 pub fn consumer(&self) -> Result<&str> {
112 // SAFETY: The string returned by libgpiod is guaranteed to live as long
113 // as the `struct Info`.
114 let name = unsafe { gpiod::gpiod_line_info_get_consumer(self.as_raw_ptr()) };
115 if name.is_null() {
116 return Err(Error::NullString("GPIO line's consumer name"));
117 }
118
119 // SAFETY: The string is guaranteed to be valid here by the C API.
120 unsafe { CStr::from_ptr(name) }
121 .to_str()
122 .map_err(Error::StringNotUtf8)
123 }
124
125 /// Get the GPIO line's direction.
126 pub fn direction(&self) -> Result<Direction> {
127 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
128 Direction::new(unsafe { gpiod::gpiod_line_info_get_direction(self.as_raw_ptr()) })
129 }
130
131 /// Returns true if the line is "active-low", false otherwise.
132 pub fn is_active_low(&self) -> bool {
133 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
134 unsafe { gpiod::gpiod_line_info_is_active_low(self.as_raw_ptr()) }
135 }
136
137 /// Get the GPIO line's bias setting.
138 pub fn bias(&self) -> Result<Option<Bias>> {
139 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
140 Bias::new(unsafe { gpiod::gpiod_line_info_get_bias(self.as_raw_ptr()) })
141 }
142
143 /// Get the GPIO line's drive setting.
144 pub fn drive(&self) -> Result<Drive> {
145 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
146 Drive::new(unsafe { gpiod::gpiod_line_info_get_drive(self.as_raw_ptr()) })
147 }
148
149 /// Get the current edge detection setting of the line.
150 pub fn edge_detection(&self) -> Result<Option<Edge>> {
151 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
152 Edge::new(unsafe { gpiod::gpiod_line_info_get_edge_detection(self.as_raw_ptr()) })
153 }
154
155 /// Get the current event clock setting used for edge event timestamps.
156 pub fn event_clock(&self) -> Result<EventClock> {
157 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
158 EventClock::new(unsafe { gpiod::gpiod_line_info_get_event_clock(self.as_raw_ptr()) })
159 }
160
161 /// Returns true if the line is debounced (either by hardware or by the
162 /// kernel software debouncer), false otherwise.
163 pub fn is_debounced(&self) -> bool {
164 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
165 unsafe { gpiod::gpiod_line_info_is_debounced(self.as_raw_ptr()) }
166 }
167
168 /// Get the debounce period of the line.
169 pub fn debounce_period(&self) -> Duration {
170 // c_ulong may be 32bit OR 64bit, clippy reports a false-positive here:
171 // https://github.com/rust-lang/rust-clippy/issues/10555
172 #[allow(clippy::unnecessary_cast)]
173 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
174 Duration::from_micros(unsafe {
175 gpiod::gpiod_line_info_get_debounce_period_us(self.as_raw_ptr()) as u64
176 })
177 }
178}
179
180/// Line info
181///
182/// This is the owned counterpart to [InfoRef]. Due to a [Deref] implementation,
183/// all functions of [InfoRef] can also be called on this type.
184#[derive(Debug)]
185pub struct Info {
186 info: *mut gpiod::gpiod_line_info,
187}
188
189// SAFETY: Info models a owned instance whose ownership may be safely
190// transferred to other threads.
191unsafe impl Send for Info {}
192
193impl Info {
194 /// Converts a owned pointer into an owned instance
195 ///
196 /// Assumes sole ownership over a [gpiod::gpiod_line_info] instance.
197 ///
198 /// SAFETY: The pointer must point to an instance that is valid. After
199 /// constructing an [Info] the pointer MUST NOT be used for any other
200 /// purpose anymore. All interactions with the libgpiod API have to happen
201 /// through this object.
202 pub(crate) unsafe fn from_raw(info: *mut gpiod::gpiod_line_info) -> Info {
203 Info { info }
204 }
205}
206
207impl Deref for Info {
208 type Target = InfoRef;
209
210 fn deref(&self) -> &Self::Target {
211 // SAFETY: The pointer is valid for the entire lifetime '0. Info is not
212 // Sync. Therefore, no &Info may be held by a different thread. Hence,
213 // the current thread owns it. Since we borrow with the lifetime of '0,
214 // no move to a different thread can occur while a reference remains
215 // being hold.
216 unsafe { InfoRef::from_raw(self.info) }
217 }
218}
219
220impl Drop for Info {
221 fn drop(&mut self) {
222 // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
223 unsafe { gpiod::gpiod_line_info_free(self.info) }
224 }
225}