power_monitor/powerd/
monitor.rs1use std::error::Error;
8use std::os::unix::io::RawFd;
9
10use base::AsRawDescriptor;
11use base::RawDescriptor;
12use base::ReadNotifier;
13use dbus::ffidisp::BusType;
14use dbus::ffidisp::Connection;
15use dbus::ffidisp::ConnectionItem;
16use dbus::ffidisp::WatchEvent;
17use protobuf::Message;
18use remain::sorted;
19use thiserror::Error;
20
21use crate::powerd::POWER_INTERFACE_NAME;
22use crate::protos::power_supply_properties::PowerSupplyProperties;
23use crate::BatteryData;
24use crate::PowerData;
25use crate::PowerMonitor;
26
27const POLL_SIGNAL_NAME: &str = "PowerSupplyPoll";
29
30#[sorted]
31#[derive(Error, Debug)]
32pub enum DBusMonitorError {
33 #[error("failed to convert protobuf message: {0}")]
34 ConvertProtobuf(protobuf::Error),
35 #[error("failed to add D-Bus match rule: {0}")]
36 DBusAddMatch(dbus::Error),
37 #[error("failed to connect to D-Bus: {0}")]
38 DBusConnect(dbus::Error),
39 #[error("failed to read D-Bus message: {0}")]
40 DBusRead(dbus::arg::TypeMismatchError),
41 #[error("multiple D-Bus fds")]
42 MultipleDBusFd,
43 #[error("no D-Bus fd")]
44 NoDBusFd,
45}
46
47pub struct DBusMonitor {
48 connection: Connection,
49 connection_fd: RawFd,
50 previous_data: Option<BatteryData>,
51}
52
53impl DBusMonitor {
54 pub fn connect() -> std::result::Result<Box<dyn PowerMonitor>, Box<dyn Error>> {
57 let connection =
58 Connection::get_private(BusType::System).map_err(DBusMonitorError::DBusConnect)?;
59 connection
60 .add_match(&format!(
61 "interface='{POWER_INTERFACE_NAME}',member='{POLL_SIGNAL_NAME}'"
62 ))
63 .map_err(DBusMonitorError::DBusAddMatch)?;
64 let fds: Vec<RawFd> = connection
66 .watch_fds()
67 .into_iter()
68 .filter(|w| w.readable())
69 .map(|w| w.fd())
70 .collect();
71 if fds.is_empty() {
72 return Err(DBusMonitorError::NoDBusFd.into());
73 }
74 if fds.len() > 1 {
75 return Err(DBusMonitorError::MultipleDBusFd.into());
76 }
77 Ok(Box::new(Self {
78 connection,
79 connection_fd: fds[0],
80 previous_data: None,
81 }))
82 }
83}
84
85fn denoise_value(new_val: u32, prev_val: u32, margin: f64) -> u32 {
86 if new_val.abs_diff(prev_val) as f64 / prev_val.min(new_val).max(1) as f64 >= margin {
87 new_val
88 } else {
89 prev_val
90 }
91}
92
93impl PowerMonitor for DBusMonitor {
94 fn read_message(&mut self) -> std::result::Result<Option<PowerData>, Box<dyn Error>> {
97 let newest_message: Option<dbus::Message> = self
99 .connection
100 .watch_handle(
101 self.connection_fd,
102 WatchEvent::Readable as std::os::raw::c_uint,
103 )
104 .fold(None, |last, item| match item {
105 ConnectionItem::Signal(message) => {
106 let interface = match message.interface() {
109 Some(i) => i,
110 None => {
111 return last;
112 }
113 };
114
115 if &*interface != POWER_INTERFACE_NAME {
116 return last;
117 }
118
119 let member = match message.member() {
120 Some(m) => m,
121 None => {
122 return last;
123 }
124 };
125
126 if &*member != POLL_SIGNAL_NAME {
127 return last;
128 }
129
130 Some(message)
131 }
132 _ => last,
133 });
134
135 let previous_data = self.previous_data.take();
136 match newest_message {
137 Some(message) => {
138 let data_bytes: Vec<u8> = message.read1().map_err(DBusMonitorError::DBusRead)?;
139 let mut props = PowerSupplyProperties::new();
140 props
141 .merge_from_bytes(&data_bytes)
142 .map_err(DBusMonitorError::ConvertProtobuf)?;
143 let mut data: PowerData = props.into();
144 if let (Some(new_data), Some(previous)) = (data.battery.as_mut(), previous_data) {
145 new_data.voltage = denoise_value(new_data.voltage, previous.voltage, 0.1);
153 new_data.current = denoise_value(new_data.current, previous.current, 0.1);
154 new_data.charge_counter =
155 denoise_value(new_data.charge_counter, previous.charge_counter, 0.01);
156 }
157 self.previous_data = data.battery;
158 Ok(Some(data))
159 }
160 None => Ok(None),
161 }
162 }
163}
164
165impl AsRawDescriptor for DBusMonitor {
166 fn as_raw_descriptor(&self) -> RawDescriptor {
167 self.connection_fd
168 }
169}
170
171impl ReadNotifier for DBusMonitor {
172 fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
173 self
174 }
175}