Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions embedded-mcu-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ pub mod time;
/// Traits for NVRAM (Non-Volatile Random Access Memory) storage and management.
mod nvram;
pub use nvram::{Nvram, NvramStorage};

pub mod watchdog;
21 changes: 21 additions & 0 deletions embedded-mcu-hal/src/watchdog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Traits for interactions with a processor's watchdog timer.

/// Feeds an existing watchdog to ensure the processor isn't reset.
pub trait Watchdog: Send {
/// An enumeration of `Watchdog` errors.
///
type Error: core::fmt::Debug;

/// Restarts the countdown on the watchdog. This must be done once the watchdog is started
/// to prevent the processor being reset.
///
fn feed(&mut self) -> Result<(), Self::Error>;
}

impl<T: Watchdog> Watchdog for &mut T {
Copy link
Contributor Author

@williampMSFT williampMSFT Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looked odd to my eye, but apparently this pattern was established in embedded-hal by rust-embedded/embedded-hal#310. I guess the idea is that this lets a function that takes an impl Watchdog as an argument be passed a &mut impl Watchdog and still work? It's not clear to me why you wouldn't just say that functions have to declare that their argument type is &mut impl Watchdog instead, but I think we want to align on what embedded-hal is doing, so I went with it. If anyone knows what the upside of doing this is I'd be interested in your take on it :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah as we discussed offline, I think this pattern makes sense in some contexts/for some traits, but for a Watchdog specifically I can't think of a particular use case. Though I don't think it will necessarily hurt to have it here anyway as if someone really wants to pass an &mut impl Watchdog to a generic function there's nothing necessarily unsafe or problematic about that, since the compiler will just complain if they try to do anything funny.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I do understand your concern that the blanket impl means a function that takes an impl Watchdog means we can't be certain if it will take an owned T or a &T and don't know if the watchdog will be dropped and thus disabled. I guess my thoughts are the user is responsible for understanding that (e.g. if they pass an owned watchdog they should understand it will be dropped).

type Error = T::Error;

fn feed(&mut self) -> Result<(), Self::Error> {
T::feed(self)
}
}