diff --git a/rs-matter-embassy/Cargo.toml b/rs-matter-embassy/Cargo.toml index d6f7a20..284fb74 100644 --- a/rs-matter-embassy/Cargo.toml +++ b/rs-matter-embassy/Cargo.toml @@ -21,8 +21,8 @@ rs-matter = { git = "https://github.com/sysgrok/rs-matter", branch = "next" } #rs-matter = { path = "../../rs-matter/rs-matter" } rs-matter-stack = { git = "https://github.com/ivmarkov/rs-matter-stack.git", branch = "next" } #rs-matter-stack = { path = "../../rs-matter-stack" } -openthread = { git = "https://github.com/sysgrok/openthread.git" } -#openthread = { version = "0.1", path = "../../../openthread/openthread" } +# Fork with set_link_mode method: https://github.com/esp-rs/openthread/pull/50 +openthread = { git = "https://github.com/lexfrei/openthread", branch = "feat/add-set-link-mode" } nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "11d5c3c3653af73b511133c2f8231f33eb0696f4" } nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "11d5c3c3653af73b511133c2f8231f33eb0696f4" } diff --git a/rs-matter-embassy/src/ot.rs b/rs-matter-embassy/src/ot.rs index cf685d2..3fc88c5 100644 --- a/rs-matter-embassy/src/ot.rs +++ b/rs-matter-embassy/src/ot.rs @@ -296,6 +296,16 @@ impl NetCtl for OtNetCtl<'_> { select(self.0.wait_changed(), Timer::after(Duration::from_secs(1))).await; } + // Enable rx_on_when_idle AFTER Thread attach so device can receive + // unsolicited messages (CASE sessions, etc.). Must be called after + // the device has joined the network, not before. + // Parameters: rx_on_when_idle=true, device_type=false (MTD), network_data=false + if let Err(e) = self.0.set_link_mode(true, false, false) { + warn!("Failed to set link mode: {:?}", e); + } else { + info!("Link mode set: rx_on_when_idle=true"); + } + Ok(()) } } @@ -421,6 +431,14 @@ impl<'d> OtMdns<'d> { /// Run the `OtMdns` instance by listening to the mDNS services and registering them with the SRP server pub async fn run(&self, matter: &Matter<'_>) -> Result<(), OtError> { + // On first iteration only: clean up any stale SRP records from previous runs. + // Using immediate removal (true) avoids blocking on slow/unreachable + // SRP servers which would consume the Matter Fail-Safe timer. + if !self.ot.srp_is_empty()? { + let _ = self.ot.srp_remove_all(true); + info!("SRP startup cleanup: removed stale records"); + } + loop { // TODO: Not very efficient to remove and re-add everything @@ -443,26 +461,6 @@ impl<'d> OtMdns<'d> { "Unreachable" ); - // If the device was restarted, this call will make sure that - // the SRP records are removed from the SRP server - let _ = self.ot.srp_set_conf(&SrpConf { - host_name: hostname.as_str(), - ..Default::default() - }); - - let _ = self.ot.srp_remove_all(false); - - // TODO: Something is still not quite right with the SRP - // We seem to get stuck here - while !self.ot.srp_is_empty()? { - debug!("Waiting for SRP records to be removed..."); - select( - Timer::after(Duration::from_secs(1)), - self.ot.srp_wait_changed(), - ) - .await; - } - self.ot.srp_set_conf(&SrpConf { host_name: hostname.as_str(), ..Default::default() diff --git a/rs-matter-embassy/src/wireless/thread.rs b/rs-matter-embassy/src/wireless/thread.rs index d779254..eef95cc 100644 --- a/rs-matter-embassy/src/wireless/thread.rs +++ b/rs-matter-embassy/src/wireless/thread.rs @@ -1,6 +1,7 @@ use core::pin::pin; -use embassy_futures::select::select3; +use embassy_futures::select::{select3, select4}; +use embassy_time::{Duration, Timer}; use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use openthread::{OpenThread, Radio}; @@ -366,8 +367,51 @@ where let mut persist = pin!(persister.run()); ot.enable_ipv6(true).map_err(to_matter_err)?; ot.srp_autostart().map_err(to_matter_err)?; + info!("SRP autostart enabled"); + + // Enable rx_on_when_idle so device can receive unsolicited messages (CASE, etc.) + // Parameters: rx_on_when_idle=true, device_type=false (MTD), network_data=false + ot.set_link_mode(true, false, false) + .map_err(to_matter_err)?; + + // SRP diagnostic task - logs status every 1 second for debugging + let ot_diag = ot.clone(); + let mut srp_diag = pin!(async { + let mut tick = 0u32; + loop { + Timer::after(Duration::from_secs(1)).await; + tick += 1; + + let server_addr = ot_diag.srp_server_addr().ok().flatten(); + + // Count services and their states + let mut total = 0u8; + let mut registered = 0u8; + let mut adding = 0u8; + let mut removing = 0u8; + let _ = ot_diag.srp_services(|svc| { + if let Some((_, state, _)) = svc { + total += 1; + match state { + openthread::SrpState::Registered => registered += 1, + openthread::SrpState::Adding | openthread::SrpState::ToAdd => adding += 1, + openthread::SrpState::Removing | openthread::SrpState::ToRemove => removing += 1, + _ => {} + } + } + }); + + if let Some(addr) = server_addr { + info!("SRP[{}s]: srv={}, reg={}/{}, add={}, rm={}", tick, addr, registered, total, adding, removing); + } else { + warn!("SRP[{}s]: NO SERVER, svc={}", tick, total); + } + } + #[allow(unreachable_code)] + Ok::<(), Error>(()) + }); - let result = select3(&mut main, &mut radio, &mut persist) + let result = select4(&mut main, &mut radio, &mut persist, &mut srp_diag) .coalesce() .await; @@ -436,6 +480,11 @@ where ot.enable_ipv6(true).map_err(to_matter_err)?; ot.srp_autostart().map_err(to_matter_err)?; + // Enable rx_on_when_idle so device can receive unsolicited messages (CASE, etc.) + // Parameters: rx_on_when_idle=true, device_type=false (MTD), network_data=false + ot.set_link_mode(true, false, false) + .map_err(to_matter_err)?; + let result = select3(&mut main, &mut radio, &mut persist) .coalesce() .await;