libgpiod/line_config.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 super::{
6 Error, OperationType, Result, gpiod,
7 line::{Offset, Settings, SettingsMap, Value},
8};
9
10/// Line configuration objects.
11///
12/// The line-config object contains the configuration for lines that can be
13/// used in two cases:
14/// - when making a line request
15/// - when reconfiguring a set of already requested lines.
16///
17/// A new line-config object is empty. Using it in a request will lead to an
18/// error. In order for a line-config to become useful, it needs to be assigned
19/// at least one offset-to-settings mapping by calling
20/// ::gpiod_line_config_add_line_settings.
21///
22/// When calling ::gpiod_chip_request_lines, the library will request all
23/// offsets that were assigned settings in the order that they were assigned.
24
25#[derive(Debug, Eq, PartialEq)]
26pub struct Config {
27 pub(crate) config: *mut gpiod::gpiod_line_config,
28}
29
30// SAFETY: Config models a wrapper around an owned gpiod_line_config and may be
31// safely sent to other threads.
32unsafe impl Send for Config {}
33
34impl Config {
35 /// Create a new line config object.
36 pub fn new() -> Result<Self> {
37 // SAFETY: The `gpiod_line_config` returned by libgpiod is guaranteed to live as long
38 // as the `struct Config`.
39 let config = unsafe { gpiod::gpiod_line_config_new() };
40
41 if config.is_null() {
42 return Err(Error::OperationFailed(
43 OperationType::LineConfigNew,
44 errno::errno(),
45 ));
46 }
47
48 Ok(Self { config })
49 }
50
51 /// Resets the entire configuration stored in the object. This is useful if
52 /// the user wants to reuse the object without reallocating it.
53 pub fn reset(&mut self) {
54 // SAFETY: `gpiod_line_config` is guaranteed to be valid here.
55 unsafe { gpiod::gpiod_line_config_reset(self.config) }
56 }
57
58 /// Add line settings for a set of offsets.
59 pub fn add_line_settings(
60 &mut self,
61 offsets: &[Offset],
62 settings: Settings,
63 ) -> Result<&mut Self> {
64 // SAFETY: `gpiod_line_config` is guaranteed to be valid here.
65 let ret = unsafe {
66 gpiod::gpiod_line_config_add_line_settings(
67 self.config,
68 offsets.as_ptr(),
69 offsets.len(),
70 settings.settings,
71 )
72 };
73
74 if ret == -1 {
75 Err(Error::OperationFailed(
76 OperationType::LineConfigAddSettings,
77 errno::errno(),
78 ))
79 } else {
80 Ok(self)
81 }
82 }
83
84 /// Set output values for a number of lines.
85 pub fn set_output_values(&mut self, values: &[Value]) -> Result<&mut Self> {
86 let mut mapped_values = Vec::new();
87 for value in values {
88 mapped_values.push(value.value());
89 }
90
91 let ret = unsafe {
92 gpiod::gpiod_line_config_set_output_values(
93 self.config,
94 mapped_values.as_ptr(),
95 values.len(),
96 )
97 };
98
99 if ret == -1 {
100 Err(Error::OperationFailed(
101 OperationType::LineConfigSetOutputValues,
102 errno::errno(),
103 ))
104 } else {
105 Ok(self)
106 }
107 }
108
109 /// Get a mapping of offsets to line settings stored by this object.
110 pub fn line_settings(&self) -> Result<SettingsMap> {
111 let mut map = SettingsMap::new();
112 // SAFETY: gpiod_line_config is guaranteed to be valid here
113 let num_lines = unsafe { gpiod::gpiod_line_config_get_num_configured_offsets(self.config) };
114 let mut offsets = vec![0; num_lines];
115
116 // SAFETY: gpiod_line_config is guaranteed to be valid here.
117 let num_stored = unsafe {
118 gpiod::gpiod_line_config_get_configured_offsets(
119 self.config,
120 offsets.as_mut_ptr(),
121 num_lines,
122 )
123 };
124
125 for offset in &offsets[0..num_stored] {
126 // SAFETY: `gpiod_line_config` is guaranteed to be valid here.
127 let settings =
128 unsafe { gpiod::gpiod_line_config_get_line_settings(self.config, *offset) };
129 if settings.is_null() {
130 return Err(Error::OperationFailed(
131 OperationType::LineConfigGetSettings,
132 errno::errno(),
133 ));
134 }
135
136 // SAFETY: The above `gpiod_line_config_get_line_settings` call
137 // returns a copy of the line_settings. We thus have sole ownership.
138 // We no longer use the pointer for any other purpose.
139 let settings = unsafe { Settings::from_raw(settings) };
140
141 map.insert(*offset as Offset, settings);
142 }
143
144 Ok(map)
145 }
146}
147
148impl Drop for Config {
149 /// Free the line config object and release all associated resources.
150 fn drop(&mut self) {
151 // SAFETY: `gpiod_line_config` is guaranteed to be valid here.
152 unsafe { gpiod::gpiod_line_config_free(self.config) }
153 }
154}