use embassy_time::{Duration, Instant}; use sachy_fmt::{debug, unwrap}; #[derive(Debug, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) enum MdnsStateMachine { #[default] Start, Announce { last_sent: Instant, }, ListenFor { last_sent: Instant, timeout: Duration, }, WaitFor { last_sent: Instant, duration: Duration, }, } impl MdnsStateMachine { /// Set the state to announced, if we have timed out the listening period and need /// to announce, or if we received a query while listening and have sent a response. pub(crate) fn announced(&mut self) { *self = Self::Announce { last_sent: Instant::now(), }; } fn next_state(&mut self) { match self { Self::Start => self.announced(), &mut Self::Announce { last_sent } => { let duration_since = last_sent.elapsed(); let duration = Duration::from_secs(1) - duration_since; *self = Self::WaitFor { last_sent, duration, }; } &mut Self::ListenFor { last_sent, .. } => { let duration_since = last_sent.elapsed(); let time_limit = Duration::from_secs(120); if duration_since >= time_limit { self.announced(); } else { let timeout = time_limit - duration_since; *self = Self::ListenFor { last_sent, timeout }; } } &mut Self::WaitFor { last_sent, .. } => { let duration_since = last_sent.elapsed(); let time_limit = Duration::from_secs(120); let timeout = time_limit - duration_since; *self = Self::ListenFor { last_sent, timeout }; } } } pub(crate) fn drive_next_action(&mut self) -> MdnsAction { self.next_state(); unwrap!(MdnsAction::try_from(self)) } } #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MdnsAction { Announce, ListenFor { timeout: Duration }, WaitFor { duration: Duration }, } impl TryFrom<&mut MdnsStateMachine> for MdnsAction { type Error = MdnsStateMachine; fn try_from(value: &mut MdnsStateMachine) -> Result { match value { // We should start in this state, but never remain nor return to it when // executing our state machine event loop. MdnsStateMachine::Start => Err(MdnsStateMachine::Start), MdnsStateMachine::Announce { .. } => { debug!("ANNOUNCE"); Ok(Self::Announce) } &mut MdnsStateMachine::ListenFor { timeout, .. } => { debug!("LISTEN FOR {}ms", timeout.as_millis()); Ok(Self::ListenFor { timeout }) } &mut MdnsStateMachine::WaitFor { duration, .. } => { debug!("WAIT FOR {}ms", duration.as_millis()); Ok(Self::WaitFor { duration }) } } } }