aboutsummaryrefslogtreecommitdiffstats
path: root/bindings/rust/libgpiod/src/line_info.rs
blob: 702f1b478decb0ebc330953fd2f062560237661a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
// SPDX-FileCopyrightText: 2022 Linaro Ltd.
// SPDX-FileCopyrightText: 2022 Viresh Kumar <viresh.kumar@linaro.org>

use std::ffi::CStr;
use std::str;
use std::time::Duration;

use super::{
    gpiod,
    line::{Bias, Direction, Drive, Edge, EventClock, Offset},
    Error, Result,
};

/// Line info
///
/// Exposes functions for retrieving kernel information about both requested and
/// free lines.  Line info object contains an immutable snapshot of a line's status.
///
/// The line info contains all the publicly available information about a
/// line, which does not include the line value.  The line must be requested
/// to access the line value.

#[derive(Debug, Eq, PartialEq)]
pub struct Info {
    info: *mut gpiod::gpiod_line_info,
    contained: bool,
}

impl Info {
    fn new_internal(info: *mut gpiod::gpiod_line_info, contained: bool) -> Result<Self> {
        Ok(Self { info, contained })
    }

    /// Get a snapshot of information about the line.
    pub(crate) fn new(info: *mut gpiod::gpiod_line_info) -> Result<Self> {
        Info::new_internal(info, false)
    }

    /// Get a snapshot of information about the line and start watching it for changes.
    pub(crate) fn new_watch(info: *mut gpiod::gpiod_line_info) -> Result<Self> {
        Info::new_internal(info, false)
    }

    /// Get the Line info object associated with an event.
    pub(crate) fn new_from_event(info: *mut gpiod::gpiod_line_info) -> Result<Self> {
        Info::new_internal(info, true)
    }

    /// Get the offset of the line within the GPIO chip.
    ///
    /// The offset uniquely identifies the line on the chip. The combination of the chip and offset
    /// uniquely identifies the line within the system.

    pub fn offset(&self) -> Offset {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        unsafe { gpiod::gpiod_line_info_get_offset(self.info) }
    }

    /// Get GPIO line's name.
    pub fn name(&self) -> Result<&str> {
        // SAFETY: The string returned by libgpiod is guaranteed to live as long
        // as the `struct Info`.
        let name = unsafe { gpiod::gpiod_line_info_get_name(self.info) };
        if name.is_null() {
            return Err(Error::NullString("GPIO line's name"));
        }

        // SAFETY: The string is guaranteed to be valid here by the C API.
        unsafe { CStr::from_ptr(name) }
            .to_str()
            .map_err(Error::StringNotUtf8)
    }

    /// Returns True if the line is in use, false otherwise.
    ///
    /// The user space can't know exactly why a line is busy. It may have been
    /// requested by another process or hogged by the kernel. It only matters that
    /// the line is used and we can't request it.
    pub fn is_used(&self) -> bool {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        unsafe { gpiod::gpiod_line_info_is_used(self.info) }
    }

    /// Get the GPIO line's consumer name.
    pub fn consumer(&self) -> Result<&str> {
        // SAFETY: The string returned by libgpiod is guaranteed to live as long
        // as the `struct Info`.
        let name = unsafe { gpiod::gpiod_line_info_get_consumer(self.info) };
        if name.is_null() {
            return Err(Error::NullString("GPIO line's consumer name"));
        }

        // SAFETY: The string is guaranteed to be valid here by the C API.
        unsafe { CStr::from_ptr(name) }
            .to_str()
            .map_err(Error::StringNotUtf8)
    }

    /// Get the GPIO line's direction.
    pub fn direction(&self) -> Result<Direction> {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        Direction::new(unsafe { gpiod::gpiod_line_info_get_direction(self.info) })
    }

    /// Returns true if the line is "active-low", false otherwise.
    pub fn is_active_low(&self) -> bool {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        unsafe { gpiod::gpiod_line_info_is_active_low(self.info) }
    }

    /// Get the GPIO line's bias setting.
    pub fn bias(&self) -> Result<Option<Bias>> {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        Bias::new(unsafe { gpiod::gpiod_line_info_get_bias(self.info) })
    }

    /// Get the GPIO line's drive setting.
    pub fn drive(&self) -> Result<Drive> {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        Drive::new(unsafe { gpiod::gpiod_line_info_get_drive(self.info) })
    }

    /// Get the current edge detection setting of the line.
    pub fn edge_detection(&self) -> Result<Option<Edge>> {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        Edge::new(unsafe { gpiod::gpiod_line_info_get_edge_detection(self.info) })
    }

    /// Get the current event clock setting used for edge event timestamps.
    pub fn event_clock(&self) -> Result<EventClock> {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        EventClock::new(unsafe { gpiod::gpiod_line_info_get_event_clock(self.info) })
    }

    /// Returns true if the line is debounced (either by hardware or by the
    /// kernel software debouncer), false otherwise.
    pub fn is_debounced(&self) -> bool {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        unsafe { gpiod::gpiod_line_info_is_debounced(self.info) }
    }

    /// Get the debounce period of the line.
    pub fn debounce_period(&self) -> Duration {
        // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
        Duration::from_micros(unsafe {
            gpiod::gpiod_line_info_get_debounce_period_us(self.info) as u64
        })
    }
}

impl Drop for Info {
    fn drop(&mut self) {
        // We must not free the Line info object created from `struct chip::Event` by calling
        // libgpiod API.
        if !self.contained {
            // SAFETY: `gpiod_line_info` is guaranteed to be valid here.
            unsafe { gpiod::gpiod_line_info_free(self.info) }
        }
    }
}