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
use std::{sync::Arc, time::Duration};
use crate::{
dbus_helpers::props::*,
types::*,
};
#[derive(Debug, Copy, Clone)]
enum Polarity {
ActiveHigh,
ActiveLow,
}
impl TryFrom<&String> for Polarity {
type Error = Box<dyn std::error::Error>;
fn try_from(s: &String) -> ErrResult<Self> {
match s.as_ref() {
"High" => Ok(Self::ActiveHigh),
"Low" => Ok(Self::ActiveLow),
_ => Err(err_invalid_data("Polarity must be \"High\" or \"Low\"")),
}
}
}
#[derive(Debug)]
pub struct BridgeGPIOConfig {
pub name: String,
setup_time: Duration,
polarity: Polarity,
}
impl BridgeGPIOConfig {
pub fn from_dbus(cfg: &dbus::arg::PropMap) -> ErrResult<Self> {
let name: &String = prop_get_mandatory(cfg, "Name")?;
let setup_sec: f64 = *prop_get_default(cfg, "SetupTime", &0.0f64)?;
let polarity = prop_get_default_from(cfg, "Polarity", Polarity::ActiveHigh)?;
Ok(Self {
name: name.clone(),
setup_time: Duration::from_secs_f64(setup_sec),
polarity,
})
}
}
pub struct BridgeGPIO {
line: gpiocdev::FoundLine,
cfg: Arc<BridgeGPIOConfig>,
req: gpiocdev::request::Request,
active: bool,
}
pub struct BridgeGPIOActivation<'a> {
gpio: &'a mut BridgeGPIO
}
impl BridgeGPIO {
pub fn from_config(cfg: Arc<BridgeGPIOConfig>) -> ErrResult<Self> {
let Some(line) = gpiocdev::find_named_line(&cfg.name) else {
eprintln!("failed to find bridge GPIO {}", cfg.name);
return Err(err_not_found("GPIO not found"));
};
fn set_sense(builder: &mut gpiocdev::request::Builder, pol: Polarity)
-> &mut gpiocdev::request::Builder
{
match pol {
Polarity::ActiveHigh => builder.as_active_high(),
Polarity::ActiveLow => builder.as_active_low(),
}
}
let req = set_sense(gpiocdev::request::Request::builder()
.with_found_line(&line)
.with_direction(gpiocdev::line::Direction::Output),
cfg.polarity)
.request()?;
Ok(Self {
line,
cfg,
req,
active: false,
})
}
pub async fn activate(&mut self) -> ErrResult<BridgeGPIOActivation<'_>> {
if self.active {
return Err(err_other("GPIO activation already held"));
}
self.req.set_value(self.line.offset, gpiocdev::line::Value::Active)?;
tokio::time::sleep(self.cfg.setup_time).await;
self.active = true;
Ok(BridgeGPIOActivation {
gpio: self,
})
}
}
impl Drop for BridgeGPIOActivation<'_> {
fn drop(&mut self) {
if let Err(e) = self.gpio.req.set_value(self.gpio.line.offset,
gpiocdev::line::Value::Inactive) {
eprintln!("failed to reset bridge gpio {}: {}", self.gpio.cfg.name, e);
}
self.gpio.active = false;
}
}