Skip to content

Commit 3e23ce4

Browse files
committed
Add SignalLevelAgent
1 parent 3331ba0 commit 3e23ce4

File tree

2 files changed

+134
-2
lines changed

2 files changed

+134
-2
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use clap::Parser;
2+
use iwdrs::station::SignalLevelAgent;
3+
4+
#[derive(Debug, Parser)]
5+
/// Connect to a Wifi Network given a SSID and optionally a password.
6+
struct Args {
7+
#[clap(allow_hyphen_values = true)]
8+
levels: Vec<i16>,
9+
}
10+
11+
#[tokio::main(flavor = "current_thread")]
12+
async fn main() {
13+
let Args { levels } = Args::parse();
14+
15+
let session = iwdrs::session::Session::new().await.unwrap();
16+
17+
let station = session.stations().pop().unwrap();
18+
19+
station
20+
.register_signal_level_agent(levels, Agent {})
21+
.await
22+
.unwrap();
23+
24+
std::future::pending::<()>().await;
25+
}
26+
27+
struct Agent {}
28+
29+
impl SignalLevelAgent for Agent {
30+
fn changed(
31+
&self,
32+
_station: &iwdrs::station::Station,
33+
signal_level: impl std::ops::RangeBounds<i16>,
34+
) {
35+
println!(
36+
"Wifi Signal Strength Min {:?} Max {:?}",
37+
signal_level.start_bound(),
38+
signal_level.end_bound()
39+
)
40+
}
41+
}

src/station.rs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
use std::{collections::HashMap, sync::Arc};
1+
use std::{
2+
cmp::Reverse,
3+
collections::HashMap,
4+
ops::{Bound, RangeBounds},
5+
sync::Arc,
6+
};
27

38
use zvariant::{OwnedObjectPath, Value};
49

5-
use zbus::{Connection, Proxy};
10+
use zbus::{Connection, Proxy, interface};
611

712
use crate::{
813
error::{
@@ -94,6 +99,39 @@ impl Station {
9499

95100
Ok(networks)
96101
}
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+
}
97135
}
98136

99137
impl StationDiagnostics {
@@ -134,3 +172,56 @@ impl StationDiagnostics {
134172
Ok(body)
135173
}
136174
}
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

Comments
 (0)