diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index c2575267..de32edc2 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -172,6 +172,7 @@ impl Config { /// /// # Example /// ```rust + /// # use embassy_net::Config; /// let _cfg = Config::dhcpv4(Default::default()); /// ``` #[cfg(feature = "dhcpv4")] @@ -226,6 +227,7 @@ struct Inner { static_v6: Option, #[cfg(feature = "dhcpv4")] dhcp_socket: Option, + config_waker: WakerRegistration, #[cfg(feature = "dns")] dns_socket: SocketHandle, #[cfg(feature = "dns")] @@ -297,6 +299,7 @@ impl Stack { static_v6: None, #[cfg(feature = "dhcpv4")] dhcp_socket: None, + config_waker: WakerRegistration::new(), #[cfg(feature = "dns")] dns_socket: socket.sockets.add(dns::Socket::new( &[], @@ -363,6 +366,55 @@ impl Stack { v4_up || v6_up } + /// Wait for the network stack to obtain a valid IP configuration. + /// + /// ## Notes: + /// - Ensure [`Stack::run`] has been called before using this function. + /// + /// - This function may never return (e.g. if no configuration is obtained through DHCP). + /// The caller is supposed to handle a timeout for this case. + /// + /// ## Example + /// ```ignore + /// let config = embassy_net::Config::dhcpv4(Default::default()); + ///// Init network stack + /// let stack = &*make_static!(embassy_net::Stack::new( + /// device, + /// config, + /// make_static!(embassy_net::StackResources::<2>::new()), + /// seed + /// )); + /// // Launch network task that runs `stack.run().await` + /// spawner.spawn(net_task(stack)).unwrap(); + /// // Wait for DHCP config + /// stack.wait_config_up().await; + /// // use the network stack + /// // ... + /// ``` + pub async fn wait_config_up(&self) { + // If the config is up already, we can return immediately. + if self.is_config_up() { + return; + } + + poll_fn(|cx| { + if self.is_config_up() { + Poll::Ready(()) + } else { + // If the config is not up, we register a waker that is woken up + // when a config is applied (static or DHCP). + trace!("Waiting for config up"); + + self.with_mut(|_, i| { + i.config_waker.register(cx.waker()); + }); + + Poll::Pending + } + }) + .await; + } + /// Get the current IPv4 configuration. /// /// If using DHCP, this will be None if DHCP hasn't been able to @@ -706,6 +758,8 @@ impl Inner { s.sockets .get_mut::(self.dns_socket) .update_servers(&dns_servers[..]); + + self.config_waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 393e60b7..5f1e62d0 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -79,7 +79,10 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index f0e280c3..01c38106 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -80,7 +80,10 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 763520ab..c32e0fdb 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -101,6 +101,9 @@ async fn main(spawner: Spawner) -> ! { // Launch network task unwrap!(spawner.spawn(net_task(&stack))); + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + info!("Network task initialized"); // Then we can use it! diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 26a386e4..e691c6d0 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -83,6 +83,9 @@ async fn main(spawner: Spawner) -> ! { // Launch network task unwrap!(spawner.spawn(net_task(&stack))); + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + info!("Network task initialized"); // Then we can use it! diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 6664410c..ebef54c3 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -82,13 +82,13 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); - // To ensure DHCP configuration before trying connect - Timer::after(Duration::from_secs(20)).await; - static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new(); let client = TcpClient::new(&stack, &STATE);