use core::marker::PhantomData;
use crate::{
regs::{self, srss::wdt_ctl},
security::{self, Security},
};
#[cfg_attr(mxs40srss, doc = "16-bit up-counter,")]
#[cfg_attr(mxs40ssrss, doc = "32-bit up-counter,")]
#[non_exhaustive]
#[derive(Debug)]
pub struct Wdt<Sec: Security = security::Default>(Sec);
cfg_select! {
mxs40srss => {
pub type Counter = u16;
}
mxs40ssrss => {
pub type Counter = u32;
},
}
impl Wdt {
pub unsafe fn steal() -> Self {
Self(security::DEFAULT)
}
}
impl<Sec: Security> Wdt<Sec> {
pub const fn with_security<New: Security>(self, new: New) -> Wdt<New> {
Wdt(new)
}
pub fn unlock(&mut self) -> UnlockedWdt<'_, Sec> {
critical_section::with(|_cs| unsafe {
let wdt_ctl = regs::SRSS.wdt_ctl().read();
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(wdt_ctl::WdtLock::CLR_0));
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(wdt_ctl::WdtLock::CLR_1));
});
UnlockedWdt(Self(self.0), PhantomData)
}
pub fn into_unlocked(mut self) -> UnlockedWdt<'static, Sec> {
self.unlock();
UnlockedWdt(Self(self.0), PhantomData)
}
}
#[derive(Debug)]
pub struct UnlockedWdt<'a, Sec: Security = security::Default>(Wdt<Sec>, PhantomData<&'a mut Wdt>);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
#[cfg(mxs40ssrss)]
pub enum ClockSource {
Ilo = 0,
Backup = 2,
}
impl<'a, Sec: Security> UnlockedWdt<'a, Sec> {
pub const fn with_security<New: Security>(self, new: New) -> UnlockedWdt<'a, New> {
UnlockedWdt(Wdt(new), PhantomData)
}
#[cfg(mxs40ssrss)]
pub fn set_clock_source(&mut self, clock_source: ClockSource) {
critical_section::with(|_cs| unsafe {
regs::SRSS.wdt_ctl().modify(|r| {
r.wdt_clk_sel()
.set(wdt_ctl::WdtClkSel::new(clock_source as u8))
})
})
}
#[cfg(mxs40ssrss)]
pub fn clock_source(&self) -> ClockSource {
critical_section::with(|_cs| unsafe {
core::mem::transmute::<u8, ClockSource>(
regs::SRSS.wdt_ctl().read().wdt_clk_sel().get().0,
)
})
}
pub fn set_enabled(&mut self, enabled: bool) {
critical_section::with(|_cs| unsafe {
regs::SRSS.wdt_ctl().modify(|r| r.wdt_en().set(enabled))
})
}
pub fn enabled(&self) -> bool {
critical_section::with(|_cs| unsafe { regs::SRSS.wdt_ctl().read().wdt_en().get() })
}
pub fn set_match_value(&mut self, value: Counter) {
unsafe { regs::SRSS.wdt_match().modify(|r| r.r#match().set(value)) }
}
pub fn match_value(&self) -> Counter {
unsafe { regs::SRSS.wdt_match().read().r#match().get() }
}
pub fn set_matched_bits(&mut self, msb: u8) {
cfg_select! {
mxs40ssrss => {
debug_assert!(msb <= 31, "msb must be at most 31");
unsafe {
regs::SRSS
.wdt_match2()
.modify(|r| r.ignore_bits_above().set(msb))
}
}
mxs40srss => {
debug_assert!(msb <= 15, "msb must be at most 15");
unsafe {
regs::SRSS
.wdt_match()
.modify(|r| r.ignore_bits().set(15 - msb))
}
}
}
}
pub fn matched_bits(&self) -> u8 {
cfg_select! {
mxs40ssrss => {
unsafe { regs::SRSS.wdt_match2().read().ignore_bits_above().get() }
}
mxs40srss => {
15 - unsafe { regs::SRSS.wdt_match().read().ignore_bits().get() }
}
}
}
pub fn lock(self) {
critical_section::with(|_cs| unsafe {
regs::SRSS
.wdt_ctl()
.modify(|r| r.wdt_lock().set(wdt_ctl::WdtLock::SET_01))
})
}
}
impl UnlockedWdt<'static> {
pub fn into_locked(self) -> Wdt {
self.lock();
unsafe { Wdt::steal() }
}
}