use core::{marker::PhantomData, ops::Deref};
#[cfg(mxs40ssrss)]
use crate::regs::srss::mcwdt_struct::mcwdt_config::{WdtLowerMode0, WdtLowerMode1};
use crate::{
regs::{
self, AsPtr, RegisterValue,
srss::{
McwdtStruct,
mcwdt_struct::{
mcwdt_config::{WdtMode0, WdtMode1, WdtMode2},
mcwdt_lock,
},
},
},
security::{self, Security, WithSecurity},
};
#[cfg_attr(
mxs40ssrss,
doc = "The 16-bit sub-counters additionally support a configurable lower limit; servicing"
)]
#[cfg_attr(
mxs40ssrss,
doc = "the watchdog before the counter reaches the lower limit can raise an interrupt or"
)]
#[cfg_attr(mxs40ssrss, doc = "reset the device.")]
#[non_exhaustive]
#[derive(Debug)]
pub struct MultiWdt<const N: u8, Sec: Security = security::Default>(Sec);
impl<const N: u8> MultiWdt<N> {
pub const unsafe fn steal() -> Self {
cfg_select! {
not(mcwdt1) => {
const { assert!(N == 0, "this device only has a single MCWDT") };
}
_ => {}
}
Self(security::DEFAULT)
}
}
impl<const N: u8, Sec: Security> MultiWdt<N, Sec> {
pub const fn with_security<New: Security>(self, sec: New) -> MultiWdt<N, New> {
MultiWdt(sec)
}
#[inline(always)]
fn regs(&self) -> McwdtStruct {
cfg_select! {
not(mcwdt1) => {
let _ = N;
regs::SRSS.mcwdt_struct().with_security(self.0)
}
_ => {
regs::SRSS.mcwdt_struct().get(N as usize).with_security(self.0)
}
}
}
#[inline(always)]
fn erased(&self) -> AnyMultiWdt<'_> {
AnyMultiWdt {
regs: self.regs(),
_p: PhantomData,
}
}
pub fn into_erased(self) -> AnyMultiWdt<'static> {
AnyMultiWdt {
regs: self.regs(),
_p: PhantomData,
}
}
pub fn as_erased(&mut self) -> AnyMultiWdt<'_> {
self.erased()
}
pub fn unlock(&mut self) -> UnlockedMultiWdt<'_, N, Sec> {
self.as_erased().unlock();
UnlockedMultiWdt {
inner: Self(self.0),
_p: PhantomData,
}
}
pub fn into_unlocked(mut self) -> UnlockedMultiWdt<'static, N, Sec> {
self.unlock();
UnlockedMultiWdt {
inner: Self(self.0),
_p: PhantomData,
}
}
pub fn counters_16bit(&self) -> (u16, u16) {
self.erased().counters_16bit()
}
pub fn counter_32bit(&self) -> u32 {
self.erased().counter_32bit()
}
pub fn config(&self) -> Config {
self.erased().config()
}
#[cfg(mxs40ssrss)]
pub fn lower_limits(&self) -> (u16, u16) {
self.erased().lower_limits()
}
pub fn wait_control(&self) {
self.erased().wait_control()
}
pub fn requested_interrupts(&self) -> InterruptSet {
self.erased().requested_interrupts()
}
pub fn masked_interrupts(&self) -> InterruptSet {
self.erased().masked_interrupts()
}
}
#[derive(Debug)]
pub struct UnlockedMultiWdt<'a, const N: u8, Sec: Security = security::Default> {
inner: MultiWdt<N, Sec>,
_p: PhantomData<&'a mut MultiWdt<N>>,
}
impl<const N: u8, Sec: Security> Deref for UnlockedMultiWdt<'_, N, Sec> {
type Target = MultiWdt<N, Sec>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, const N: u8> UnlockedMultiWdt<'a, N> {
pub fn with_security<New: Security>(self, sec: New) -> UnlockedMultiWdt<'a, N, New> {
UnlockedMultiWdt {
inner: self.inner.with_security(sec),
_p: PhantomData,
}
}
#[inline(always)]
fn erased(&mut self) -> AnyUnlockedMultiWdt<'_> {
AnyUnlockedMultiWdt {
regs: self.regs(),
_p: PhantomData,
}
}
pub fn as_erased(&mut self) -> AnyUnlockedMultiWdt<'_> {
self.erased()
}
pub fn set_config(&mut self, config: Config) {
self.erased().set_config(config)
}
pub fn set_control(&mut self, ctl: Control) {
self.erased().set_control(ctl)
}
pub fn set_match_16bit(&mut self, counter0: u16, counter1: u16) {
self.erased().set_match_16bit(counter0, counter1)
}
#[cfg(mxs40ssrss)]
pub fn set_lower_limits(&mut self, counter0: u16, counter1: u16) {
self.erased().set_lower_limits(counter0, counter1)
}
pub fn enable_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
self.erased().enable_interrupts(interrupts)
}
pub fn disable_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
self.erased().disable_interrupts(interrupts)
}
pub fn set_enabled_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
self.erased().set_enabled_interrupts(interrupts)
}
pub fn clear_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
self.erased().clear_interrupts(interrupts)
}
}
impl<const N: u8> UnlockedMultiWdt<'static, N> {
pub const unsafe fn steal() -> Self {
unsafe {
UnlockedMultiWdt {
inner: MultiWdt::<N>::steal(),
_p: PhantomData,
}
}
}
}
impl<const N: u8, Sec: Security> UnlockedMultiWdt<'static, N, Sec> {
pub fn into_erased(self) -> AnyUnlockedMultiWdt<'static> {
AnyUnlockedMultiWdt {
regs: self.regs(),
_p: PhantomData,
}
}
pub fn lock(self) {
unsafe {
self.regs()
.mcwdt_lock()
.modify(|r| r.mcwdt_lock().set(mcwdt_lock::McwdtLock::SET_01))
}
}
pub fn into_locked(self) -> MultiWdt<N> {
self.lock();
unsafe { MultiWdt::steal() }
}
}
impl<const N: u8> From<MultiWdt<N>> for AnyMultiWdt<'static> {
fn from(wdt: MultiWdt<N>) -> Self {
wdt.into_erased()
}
}
impl<'a, const N: u8> From<&'a mut MultiWdt<N>> for AnyMultiWdt<'a> {
fn from(wdt: &'a mut MultiWdt<N>) -> Self {
wdt.as_erased()
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct InterruptSet(u8);
impl InterruptSet {
pub const fn new() -> Self {
Self(0)
}
pub const fn all() -> Self {
Self(0b111)
}
pub const fn contains(self, subcounter: SubCounter) -> bool {
self.0 & (1 << subcounter as u8) != 0
}
pub const fn insert(mut self, subcounter: SubCounter) -> Self {
self.0 |= 1 << subcounter as u8;
self
}
pub const fn remove(mut self, subcounter: SubCounter) -> Self {
self.0 &= !(1 << subcounter as u8);
self
}
}
impl From<SubCounter> for InterruptSet {
fn from(value: SubCounter) -> Self {
Self::new().insert(value)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Config {
pub mode_16bit_0: MatchAction,
pub cascade_0_1: CascadeMode,
pub clear_on_match_0: bool,
pub mode_16bit_1: MatchAction,
pub cascade_1_2: CascadeMode,
pub clear_on_match_1: bool,
pub interrupt_bit_32bit: Option<u8>,
#[cfg(mxs40ssrss)]
pub lower_mode_16bit_0: LowerMatchAction,
#[cfg(mxs40ssrss)]
pub require_double_match_0_1: bool,
#[cfg(mxs40ssrss)]
pub lower_mode_16bit_1: LowerMatchAction,
#[cfg(mxs40ssrss)]
pub require_double_match_1_2: bool,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum MatchAction {
#[default]
None = 0,
Interrupt = 1,
Reset = 2,
InterruptThenReset = 3,
}
#[cfg(mxs40ssrss)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum LowerMatchAction {
#[default]
None = 0,
Interrupt = 1,
Reset = 2,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum CascadeMode {
#[default]
Independent,
CarryOnMatch,
#[cfg(mxs40ssrss)]
CarryOnRollover,
}
impl CascadeMode {
#[inline(always)]
fn from_bits(cascade: bool, #[cfg(mxs40ssrss)] carry_on_rollover: bool) -> Self {
if !cascade {
return Self::Independent;
}
cfg_select! {
mxs40ssrss => {
if carry_on_rollover {
Self::CarryOnRollover
} else {
Self::CarryOnMatch
}
}
_ => Self::CarryOnMatch,
}
}
#[inline(always)]
fn to_bits(self) -> (bool, bool) {
match self {
Self::Independent => (false, false),
Self::CarryOnMatch => (true, false),
#[cfg(mxs40ssrss)]
Self::CarryOnRollover => (true, true),
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Control {
pub reset_16bit_0: bool,
pub enable_16bit_0: bool,
pub reset_16bit_1: bool,
pub enable_16bit_1: bool,
pub reset_32bit: bool,
pub enable_32bit: bool,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[allow(non_camel_case_types)]
pub enum SubCounter {
_16bit_0 = 0,
_16bit_1 = 1,
_32bit = 2,
}
#[non_exhaustive]
pub struct AnyMultiWdt<'a> {
regs: McwdtStruct,
_p: PhantomData<&'a ()>,
}
impl core::fmt::Debug for AnyMultiWdt<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("AnyMultiWdt")
.field("regs", &self.regs.as_ptr())
.finish()
}
}
impl<'a> AnyMultiWdt<'a> {
pub fn with_security<Sec: Security>(self, sec: Sec) -> AnyMultiWdt<'a> {
AnyMultiWdt {
regs: self.regs.with_security(sec),
_p: PhantomData,
}
}
pub fn reborrow(&mut self) -> AnyMultiWdt<'_> {
AnyMultiWdt {
regs: self.regs,
_p: PhantomData,
}
}
pub fn unlock(&mut self) -> AnyUnlockedMultiWdt<'_> {
unsafe {
self.regs
.mcwdt_lock()
.init(|r| r.mcwdt_lock().set(mcwdt_lock::McwdtLock::CLR_0));
self.regs
.mcwdt_lock()
.init(|r| r.mcwdt_lock().set(mcwdt_lock::McwdtLock::CLR_1));
}
AnyUnlockedMultiWdt {
regs: self.regs,
_p: PhantomData,
}
}
pub fn into_unlocked(mut self) -> AnyUnlockedMultiWdt<'static> {
self.unlock();
AnyUnlockedMultiWdt {
regs: self.regs,
_p: PhantomData,
}
}
pub fn counters_16bit(&self) -> (u16, u16) {
let v = unsafe { self.regs.mcwdt_cntlow().read() };
(v.wdt_ctr0().get(), v.wdt_ctr1().get())
}
pub fn counter_32bit(&self) -> u32 {
unsafe { self.regs.mcwdt_cnthigh().read().wdt_ctr2().get() }
}
pub fn config(&self) -> Config {
unsafe {
let v = self.regs.mcwdt_config().read();
Config {
mode_16bit_0: core::mem::transmute::<u8, MatchAction>(v.wdt_mode0().get().0),
cascade_0_1: CascadeMode::from_bits(
v.wdt_cascade0_1().get(),
#[cfg(mxs40ssrss)]
v.wdt_carry0_1().get(),
),
clear_on_match_0: v.wdt_clear0().get(),
mode_16bit_1: core::mem::transmute::<u8, MatchAction>(v.wdt_mode1().get().0),
cascade_1_2: CascadeMode::from_bits(
v.wdt_cascade1_2().get(),
#[cfg(mxs40ssrss)]
v.wdt_carry1_2().get(),
),
clear_on_match_1: v.wdt_clear1().get(),
interrupt_bit_32bit: (v.wdt_mode2().get().0 != 0).then(|| v.wdt_bits2().get()),
#[cfg(mxs40ssrss)]
lower_mode_16bit_0: core::mem::transmute::<u8, LowerMatchAction>(
v.wdt_lower_mode0().get().0,
),
#[cfg(mxs40ssrss)]
require_double_match_0_1: v.wdt_match0_1().get(),
#[cfg(mxs40ssrss)]
lower_mode_16bit_1: core::mem::transmute::<u8, LowerMatchAction>(
v.wdt_lower_mode1().get().0,
),
#[cfg(mxs40ssrss)]
require_double_match_1_2: v.wdt_match1_2().get(),
}
}
}
#[cfg(mxs40ssrss)]
pub fn lower_limits(&self) -> (u16, u16) {
let v = unsafe { self.regs.mcwdt_lower_limit().read() };
(v.wdt_lower_limit0().get(), v.wdt_lower_limit1().get())
}
pub fn wait_control(&self) {
loop {
let v = unsafe { self.regs.mcwdt_ctl().read() };
if v.wdt_reset0().get() || v.wdt_reset1().get() || v.wdt_reset2().get() {
continue;
}
if v.wdt_enable0().get() != v.wdt_enabled0().get() {
continue;
}
if v.wdt_enable1().get() != v.wdt_enabled1().get() {
continue;
}
if v.wdt_enable2().get() != v.wdt_enabled2().get() {
continue;
}
break;
}
}
pub fn requested_interrupts(&self) -> InterruptSet {
unsafe {
let bits = self.regs.mcwdt_intr().read().get_raw();
InterruptSet(bits as u8 & InterruptSet::all().0)
}
}
pub fn masked_interrupts(&self) -> InterruptSet {
unsafe {
let bits = self.regs.mcwdt_intr_masked().read().get_raw();
InterruptSet(bits as u8 & InterruptSet::all().0)
}
}
}
pub struct AnyUnlockedMultiWdt<'a> {
regs: McwdtStruct,
_p: PhantomData<&'a ()>,
}
impl core::fmt::Debug for AnyUnlockedMultiWdt<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("AnyUnlockedMultiWdt")
.field("regs", &self.regs.as_ptr())
.finish()
}
}
impl Deref for AnyUnlockedMultiWdt<'_> {
type Target = AnyMultiWdt<'static>;
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self as *const AnyMultiWdt<'static>) }
}
}
impl<'a> AnyUnlockedMultiWdt<'a> {
pub fn with_security<Sec: Security>(self, sec: Sec) -> AnyMultiWdt<'a> {
AnyMultiWdt {
regs: self.regs.with_security(sec),
_p: PhantomData,
}
}
pub fn reborrow(&mut self) -> AnyUnlockedMultiWdt<'_> {
AnyUnlockedMultiWdt {
regs: self.regs,
_p: PhantomData,
}
}
pub fn set_config(&mut self, config: Config) {
let (mode_32bit, bits_32bit) = match config.interrupt_bit_32bit {
Some(bit) => {
debug_assert!(bit <= 31, "interrupt_bit_32bit must be at most 31");
(1, bit)
}
None => (0, 0),
};
let (cascade_0_1, carry_0_1) = config.cascade_0_1.to_bits();
let (cascade_1_2, carry_1_2) = config.cascade_1_2.to_bits();
let _ = (carry_0_1, carry_1_2);
unsafe {
self.regs.mcwdt_config().init(|r| {
let r = r
.wdt_mode0()
.set(WdtMode0::new(config.mode_16bit_0 as u8))
.wdt_clear0()
.set(config.clear_on_match_0)
.wdt_cascade0_1()
.set(cascade_0_1)
.wdt_mode1()
.set(WdtMode1::new(config.mode_16bit_1 as u8))
.wdt_clear1()
.set(config.clear_on_match_1)
.wdt_cascade1_2()
.set(cascade_1_2)
.wdt_mode2()
.set(WdtMode2::new(mode_32bit))
.wdt_bits2()
.set(bits_32bit);
cfg_select! {
mxs40ssrss => {
r.wdt_carry0_1()
.set(carry_0_1)
.wdt_match0_1()
.set(config.require_double_match_0_1)
.wdt_lower_mode0()
.set(WdtLowerMode0::new(config.lower_mode_16bit_0 as u8))
.wdt_carry1_2()
.set(carry_1_2)
.wdt_match1_2()
.set(config.require_double_match_1_2)
.wdt_lower_mode1()
.set(WdtLowerMode1::new(config.lower_mode_16bit_1 as u8))
}
_ => r,
}
})
}
}
pub fn set_control(&mut self, ctl: Control) {
unsafe {
self.regs.mcwdt_ctl().init(|r| {
r.wdt_reset0()
.set(ctl.reset_16bit_0)
.wdt_enable0()
.set(ctl.enable_16bit_0)
.wdt_reset1()
.set(ctl.reset_16bit_1)
.wdt_enable1()
.set(ctl.enable_16bit_1)
.wdt_reset2()
.set(ctl.reset_32bit)
.wdt_enable2()
.set(ctl.enable_32bit)
})
}
}
pub fn set_match_16bit(&mut self, counter0: u16, counter1: u16) {
unsafe {
self.regs
.mcwdt_match()
.init(|r| r.wdt_match0().set(counter0).wdt_match1().set(counter1));
}
}
#[cfg(mxs40ssrss)]
pub fn set_lower_limits(&mut self, counter0: u16, counter1: u16) {
unsafe {
self.regs.mcwdt_lower_limit().init(|r| {
r.wdt_lower_limit0()
.set(counter0)
.wdt_lower_limit1()
.set(counter1)
});
}
}
pub fn enable_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
let mask = interrupts.into().0 as u32;
unsafe {
self.regs
.mcwdt_intr_mask()
.modify(|r| r.set_raw(r.get_raw() | mask));
}
}
pub fn disable_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
let mask = interrupts.into().0 as u32;
unsafe {
self.regs
.mcwdt_intr_mask()
.modify(|r| r.set_raw(r.get_raw() & !mask));
}
}
pub fn set_enabled_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
let mask = interrupts.into().0 as u32;
unsafe {
self.regs.mcwdt_intr_mask().init(|r| r.set_raw(mask));
}
}
pub fn clear_interrupts(&mut self, interrupts: impl Into<InterruptSet>) {
let mask = interrupts.into().0 as u32;
unsafe {
self.regs.mcwdt_intr().init(|r| r.set_raw(mask));
}
}
}
impl AnyUnlockedMultiWdt<'static> {
pub fn lock(self) {
unsafe {
self.regs
.mcwdt_lock()
.modify(|r| r.mcwdt_lock().set(mcwdt_lock::McwdtLock::SET_01))
}
}
pub fn into_locked(self) -> AnyMultiWdt<'static> {
let regs = self.regs;
self.lock();
AnyMultiWdt {
regs,
_p: PhantomData,
}
}
}