use crate::cortex_m::interrupt;
use crate::{pac::WDOG, HALExt};
use core::marker::PhantomData;
#[inline(always)]
fn unlock(_cs: &interrupt::CriticalSection) {
let peripheral = unsafe { &(*WDOG::ptr()) };
peripheral
.wdog_cnt()
.write(|w| unsafe { w.bits(0x20C5).bits(0x28D9) });
}
impl HALExt for WDOG {
type T = WatchDog<Enabled, Unlocked>;
fn split(self) -> WatchDog<Enabled, Unlocked> {
WatchDog {
_enable: PhantomData,
_update: PhantomData,
peripheral: self,
}
}
}
#[derive(Clone, Debug)]
#[repr(u8)]
pub enum WDogClock {
BusClock = 0,
LpoClock = 1,
IntRefClock = 2,
ExtRefClock = 3,
}
pub struct WatchDog<State, UpdateState> {
_enable: PhantomData<State>,
_update: PhantomData<UpdateState>,
peripheral: WDOG,
}
#[derive(Debug)]
pub struct WDogConfig {
pub interrupt: bool,
pub debug_mode: bool,
pub wait_mode: bool,
pub stop_mode: bool,
pub windowed: bool,
pub prescale: bool,
pub clock: WDogClock,
pub period: u16,
pub window: u16,
}
impl WatchDog<Enabled, Unlocked> {
pub fn configure(self, config: WDogConfig) -> WatchDog<Enabled, Locked> {
self.peripheral
.wdog_toval()
.write(|w| unsafe { w.bits(config.period.swap_bytes()) });
if config.windowed {
self.peripheral
.wdog_win()
.write(|w| unsafe { w.bits(config.window.swap_bytes()) });
}
self.peripheral.cs2.modify(|_, w| {
w.win()
.bit(config.windowed)
.pres()
.bit(config.prescale)
.clk()
.bits(config.clock.clone() as u8) });
self.peripheral.cs1.modify(|_, w| {
w.int()
.bit(config.interrupt)
.dbg()
.bit(config.debug_mode)
.wait()
.bit(config.wait_mode)
.stop()
.bit(config.stop_mode)
.en() ._1()
.update() ._1()
});
WatchDog {
_enable: PhantomData,
_update: PhantomData,
peripheral: self.peripheral,
}
}
pub fn into_disabled(self) -> WatchDog<Disabled, Locked> {
self.peripheral
.wdog_toval()
.modify(|r, w| unsafe { w.bits(r.bits()) });
if self.peripheral.cs2.read().win().bit() {
self.peripheral
.wdog_win()
.modify(|r, w| unsafe { w.bits(r.bits()) });
}
self.peripheral
.cs2
.modify(|r, w| unsafe { w.bits(r.bits()) });
self.peripheral
.cs1
.modify(|r, w| unsafe { w.bits(r.bits()).en()._0() });
WatchDog {
_enable: PhantomData,
_update: PhantomData,
peripheral: self.peripheral,
}
}
}
impl WatchDog<Enabled, Locked> {
pub fn into_disabled(self) -> WatchDog<Disabled, Locked> {
interrupt::free(|cs| {
unlock(cs);
WatchDog::<Enabled, Unlocked> {
_enable: PhantomData,
_update: PhantomData,
peripheral: self.peripheral,
}
.into_disabled()
})
}
}
impl<UpdateState> WatchDog<Enabled, UpdateState> {
pub fn service(&self) {
interrupt::free(|_| {
self.peripheral
.wdog_cnt()
.write(|w| unsafe { w.cnt().bits(0x02A6) });
self.peripheral
.wdog_cnt()
.write(|w| unsafe { w.cnt().bits(0x80B4) });
});
}
pub fn counts(&self) -> u16 {
self.peripheral.wdog_cnt().read().bits().swap_bytes()
}
}
impl<State> WatchDog<State, Locked> {
pub fn configure(self, config: WDogConfig) -> WatchDog<Enabled, Locked> {
interrupt::free(|cs| {
unlock(cs);
WatchDog::<Enabled, Unlocked> {
_enable: PhantomData,
_update: PhantomData,
peripheral: self.peripheral,
}
.configure(config)
})
}
pub fn into_sealed(self) -> WatchDog<State, Sealed> {
interrupt::free(|cs| {
unlock(cs);
self.peripheral
.wdog_toval()
.modify(|r, w| unsafe { w.bits(r.bits()) });
if self.peripheral.cs2.read().win().bit() {
self.peripheral
.wdog_win()
.modify(|r, w| unsafe { w.bits(r.bits()) });
}
self.peripheral
.cs2
.modify(|r, w| unsafe { w.bits(r.bits()) });
self.peripheral
.cs1
.modify(|r, w| unsafe { w.bits(r.bits()).update()._0() });
});
WatchDog {
_enable: PhantomData,
_update: PhantomData,
peripheral: self.peripheral,
}
}
}
impl<State, UpdateState> WatchDog<State, UpdateState> {
pub fn configuration(&self) -> WDogConfig {
WDogConfig {
interrupt: self.peripheral.cs1.read().int().bit(),
debug_mode: self.peripheral.cs1.read().dbg().bit(),
wait_mode: self.peripheral.cs1.read().wait().bit(),
stop_mode: self.peripheral.cs1.read().stop().bit(),
windowed: self.peripheral.cs2.read().win().bit(),
prescale: self.peripheral.cs2.read().pres().bit(),
clock: match self.peripheral.cs2.read().clk().bits() {
0 => WDogClock::BusClock,
1 => WDogClock::LpoClock,
2 => WDogClock::IntRefClock,
_ => WDogClock::ExtRefClock,
},
period: self.peripheral.wdog_toval().read().bits(),
window: self.peripheral.wdog_win().read().bits(),
}
}
pub fn interrupt_ran(&self, acknowledge: bool) -> bool {
let ret_val: bool = self.peripheral.cs2.read().flg().bit();
if acknowledge && ret_val {
self.peripheral.cs2.modify(|_, w| w.flg()._1());
}
ret_val
}
}
pub struct Unlocked;
pub struct Locked;
pub struct Sealed;
pub struct Enabled;
pub struct Disabled;