|
1 |
| -use std::{collections::HashMap, sync::Arc}; |
| 1 | +use std::{ |
| 2 | + cmp::Reverse, |
| 3 | + collections::HashMap, |
| 4 | + ops::{Bound, RangeBounds}, |
| 5 | + sync::Arc, |
| 6 | +}; |
2 | 7 |
|
3 | 8 | use zvariant::{OwnedObjectPath, Value};
|
4 | 9 |
|
5 |
| -use zbus::{Connection, Proxy}; |
| 10 | +use zbus::{Connection, Proxy, interface}; |
6 | 11 |
|
7 | 12 | use crate::{
|
8 | 13 | error::{
|
@@ -94,6 +99,39 @@ impl Station {
|
94 | 99 |
|
95 | 100 | Ok(networks)
|
96 | 101 | }
|
| 102 | + |
| 103 | + /// Register the agent object to receive signal strength level change notifications on the provided agent. |
| 104 | + /// The "levels" parameters decides the thresholds in dBm that will generate a call to the |
| 105 | + /// [`SignalLevelAgent::changed`] method whenever current RSSI crosses any of the values. The number and distance between |
| 106 | + /// requested threshold values is a compromise between resolution and the frequency of system wakeups and |
| 107 | + /// context-switches that are going to be occurring to update the client's signal meter. Only one agent |
| 108 | + /// can be registered at any time. |
| 109 | + pub async fn register_signal_level_agent( |
| 110 | + &self, |
| 111 | + mut levels: Vec<i16>, |
| 112 | + agent: impl SignalLevelAgent, |
| 113 | + ) -> zbus::Result<()> { |
| 114 | + // Signal level boundaries should be sorted |
| 115 | + levels.sort_by_key(|signal_level| Reverse(*signal_level)); |
| 116 | + |
| 117 | + let proxy = self.proxy().await?; |
| 118 | + |
| 119 | + let interface = SignalLevelInterface { |
| 120 | + agent, |
| 121 | + connection: self.connection.clone(), |
| 122 | + levels: levels.clone(), |
| 123 | + }; |
| 124 | + |
| 125 | + self.connection |
| 126 | + .object_server() |
| 127 | + .at(self.dbus_path.clone(), interface) |
| 128 | + .await?; |
| 129 | + |
| 130 | + proxy |
| 131 | + .call_method("RegisterSignalLevelAgent", &(&self.dbus_path, levels)) |
| 132 | + .await?; |
| 133 | + Ok(()) |
| 134 | + } |
97 | 135 | }
|
98 | 136 |
|
99 | 137 | impl StationDiagnostics {
|
@@ -134,3 +172,56 @@ impl StationDiagnostics {
|
134 | 172 | Ok(body)
|
135 | 173 | }
|
136 | 174 | }
|
| 175 | + |
| 176 | +pub trait SignalLevelAgent: Send + Sync + 'static { |
| 177 | + /// This method gets called when the service daemon unregisters the agent. An agent can use it to do |
| 178 | + /// cleanup tasks. There is no need to unregister the agent, because when this method gets called it has |
| 179 | + /// already been unregistered. |
| 180 | + fn release(&self) {} |
| 181 | + |
| 182 | + fn changed(&self, station: &Station, signal_level: impl RangeBounds<i16>); |
| 183 | +} |
| 184 | + |
| 185 | +pub struct SignalLevelInterface<A> { |
| 186 | + agent: A, |
| 187 | + connection: Arc<Connection>, |
| 188 | + levels: Vec<i16>, |
| 189 | +} |
| 190 | + |
| 191 | +#[interface(name = "net.connman.iwd.SignalLevelAgent")] |
| 192 | +impl<A: SignalLevelAgent> SignalLevelInterface<A> { |
| 193 | + #[zbus(name = "Release")] |
| 194 | + fn release(&self) { |
| 195 | + self.agent.release(); |
| 196 | + } |
| 197 | + |
| 198 | + /// This method gets called when the signal strength measurement for the device's connected network changes |
| 199 | + /// enough to go from one level to another out of the N ranges defined by the array of (N-1) threshold values |
| 200 | + /// passed to RegisterSignalLevelAgent(). It also gets registered. The level parameter is in the range from 0 |
| 201 | + /// called immediately after the signal level agent is to N, 0 being the strongest signal or above the first |
| 202 | + /// threshold value in the array, and N being the weakest and below the last threshold value. For example if |
| 203 | + /// RegisterSignalLevelAgent was called with the array [-40, -50, -60], the 'level' parameter of 0 would mean signal |
| 204 | + /// is received at -40 or more dBm and 3 would mean below -60 dBm and might correspond to 1 out of 4 bars on a UI |
| 205 | + /// signal meter. |
| 206 | + #[zbus(name = "Changed")] |
| 207 | + fn changed(&self, station_path: OwnedObjectPath, level_idx: u8) { |
| 208 | + let station = Station { |
| 209 | + connection: self.connection.clone(), |
| 210 | + dbus_path: station_path, |
| 211 | + }; |
| 212 | + |
| 213 | + let level_idx = usize::from(level_idx); |
| 214 | + let max_strength = self |
| 215 | + .levels |
| 216 | + .get(level_idx - 1) |
| 217 | + .map(|level| Bound::Excluded(*level)) |
| 218 | + .unwrap_or(Bound::Unbounded); |
| 219 | + let min_strength = self |
| 220 | + .levels |
| 221 | + .get(level_idx) |
| 222 | + .map(|level| Bound::Included(*level)) |
| 223 | + .unwrap_or(Bound::Unbounded); |
| 224 | + |
| 225 | + self.agent.changed(&station, (min_strength, max_strength)) |
| 226 | + } |
| 227 | +} |
0 commit comments