Skip to content

Commit

Permalink
Option to notify user when the netif state changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmarkov committed May 12, 2024
1 parent d621f72 commit 80866f3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ log = { version = "0.4", default-features = false }
heapless = "0.8"
enumset = { version = "1", default-features = false }
strum = { version = "0.26", default-features = false, features = ["derive"] }
scopeguard = { version = "1", default-features = false }
embassy-futures = "0.1"
embassy-sync = "0.5"
embassy-time = { version = "0.3", features = ["generic-queue"] }
Expand Down
2 changes: 1 addition & 1 deletion src/netif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const TIMEOUT_PERIOD_SECS: u8 = 5;
///
/// Allows sharing the network interface between multiple tasks, where one task
/// may be waiting for the network interface to be ready, while the other might
/// be mutable operating on the L2 driver below the netif, or on the netif itself.
/// be mutably operating on the L2 driver below the netif, or on the netif itself.
pub trait NetifAccess {
/// Waits until the network interface is available and then
/// calls the provided closure with a reference to the network interface.
Expand Down
55 changes: 55 additions & 0 deletions src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use rs_matter::utils::buf::{BufferAccess, PooledBuffers};
use rs_matter::utils::epoch::Epoch;
use rs_matter::utils::rand::Rand;
use rs_matter::utils::select::Coalesce;
use rs_matter::utils::signal::Signal;
use rs_matter::{handler_chain_type, CommissioningData, Matter, MATTER_PORT};

use crate::error::Error;
Expand Down Expand Up @@ -91,6 +92,15 @@ impl MdnsType {
}
}

/// A structure for user code that needs to be aware when the IP network is up
/// and what are its settings
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IpInfo {
pub ipv4: Ipv4Addr,
pub ipv6: Ipv6Addr,
pub interface: u32,
}

/// The `MatterStack` struct is the main entry point for the Matter stack.
///
/// It wraps the actual `rs-matter` Matter instance and provides a simplified API for running the stack.
Expand All @@ -106,6 +116,7 @@ where
network: N,
#[allow(unused)]
mdns: MdnsType,
ip_info: Signal<NoopRawMutex, Option<IpInfo>>,
}

impl<'a, N> MatterStack<'a, N>
Expand All @@ -130,6 +141,7 @@ where
subscriptions: Subscriptions::new(),
network: N::INIT,
mdns,
ip_info: Signal::new(None),
}
}

Expand All @@ -156,6 +168,24 @@ where
self.subscriptions.notify_changed();
}

/// User code hook to get the IP state of the netif passed to the
/// `run_with_netif` method.
///
/// Useful when user code needs to bring up/down its own IP services depending on
/// when the netif controlled by Matter goes up, down or changes its IP configuration.
pub async fn get_ip(&self) -> Option<IpInfo> {
self.ip_info.wait(|ip_info| Some(ip_info.clone())).await
}

/// User code hook to detect changes to the IP state of the netif passed to the
/// `run_with_netif` method.
///
/// Useful when user code needs to bring up/down its own IP services depending on
/// when the netif controlled by Matter goes up, down or changes its IP configuration.
pub async fn wait_ip_changed(&self, prev_ip_info: Option<&IpInfo>) -> Option<IpInfo> {
self.ip_info.wait(|ip_info| (ip_info.as_ref() != prev_ip_info).then(|| ip_info.clone())).await
}

/// This method is a specialization of `run_with_transport` over the UDP transport (both IPv4 and IPv6).
/// It calls `run_with_transport` and in parallel runs the mDNS service.
///
Expand All @@ -177,12 +207,37 @@ where
loop {
info!("Waiting for the network to come up...");

let reset_ip_info = || {
self.ip_info.modify(|ip_info| {
if ip_info.is_some() {
*ip_info = None;
(true, ())
} else {
(false, ())
}
});
};

let _guard = scopeguard::guard((), |_| reset_ip_info());

reset_ip_info();

let (ipv4, ipv6, interface) = netif
.wait(sysloop.clone(), |netif| Ok(get_ips(netif).ok()))
.await?;

info!("Got network with IPs: IPv4={ipv4}, IPv6={ipv6}, if={interface}");

self.ip_info.modify(|ip_info| {
*ip_info = Some(IpInfo {
ipv4,
ipv6,
interface,
});

(true, ())
});

let socket = async_io::Async::<std::net::UdpSocket>::bind(SocketAddr::V6(
SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, MATTER_PORT, 0, interface),
))?;
Expand Down

0 comments on commit 80866f3

Please sign in to comment.