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}