#![allow(missing_docs)]
use e310x::{Backup, Pmu, Rtc};
const BACKUP_REGISTER_BYTES: usize = 4;
const BACKUP_LEN: usize = 16;
pub const PMU_KEY_VAL: u32 = 0x51F15E;
#[cfg(not(feature = "g002"))]
const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [
0x0F0, 0x1F0, 0x1D0, 0x1C0, 0x1C0, 0x1C0, 0x1C0, 0x1C0,
];
#[cfg(not(feature = "g002"))]
const DEFAULT_WAKE_PROGRAM: [u32; 8] = [
0x1F0, 0x0F8, 0x030, 0x030, 0x030, 0x030, 0x030, 0x030,
];
#[cfg(feature = "g002")]
const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [
0x2F0, 0x3F0, 0x3D0, 0x3C0, 0x3C0, 0x3C0, 0x3C0, 0x3C0,
];
#[cfg(feature = "g002")]
const DEFAULT_WAKE_PROGRAM: [u32; 8] = [
0x3F0, 0x2F8, 0x030, 0x030, 0x030, 0x030, 0x030, 0x030,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResetCause {
PowerOn,
External,
WatchDog,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WakeupCause {
Reset(ResetCause),
RTC,
Digital,
}
#[derive(Debug)]
pub enum BackupError {
DataTooLarge,
DataSizeInvalid,
}
#[derive(Debug)]
pub enum CauseError {
InvalidCause,
}
pub trait PMUExt {
fn load_default_programs(&self);
fn sleep(self, sleep_time: u32);
fn wakeup_cause(&self) -> Result<WakeupCause, CauseError>;
unsafe fn store_backup<UD>(&self, user_data: &UD) -> Result<(), BackupError>;
unsafe fn restore_backup<UD>(&self, user_data: &mut UD) -> Result<(), BackupError>;
fn clear_backup(&self);
}
impl PMUExt for Pmu {
fn load_default_programs(&self) {
unsafe {
for i in 0..8 {
self.pmukey().write(|w| w.bits(PMU_KEY_VAL));
self.pmusleeppm(i)
.write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i]));
self.pmukey().write(|w| w.bits(PMU_KEY_VAL));
self.pmuwakepm(i).write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i]));
}
}
}
fn sleep(self, sleep_time: u32) {
unsafe {
let rtc = Rtc::steal();
self.pmukey().write(|w| w.bits(PMU_KEY_VAL));
self.pmuie()
.write(|w| w.rtc().set_bit().dwakeup().set_bit());
rtc.rtccfg()
.write(|w| w.enalways().set_bit().scale().bits(15));
let rtc_now = rtc.rtcs().read().bits();
rtc.rtccmp().write(|w| w.bits(rtc_now + sleep_time));
self.pmukey().write(|w| w.bits(PMU_KEY_VAL));
self.pmusleep().write(|w| w.sleep().set_bit());
}
}
fn wakeup_cause(&self) -> Result<WakeupCause, CauseError> {
let pmu_cause = self.pmucause().read();
let wakeup_cause = pmu_cause.wakeupcause();
if wakeup_cause.is_rtc() {
return Ok(WakeupCause::RTC);
} else if wakeup_cause.is_digital() {
return Ok(WakeupCause::Digital);
} else if wakeup_cause.is_reset() {
let reset_cause = pmu_cause.resetcause();
if reset_cause.is_power_on() {
return Ok(WakeupCause::Reset(ResetCause::PowerOn));
} else if reset_cause.is_external() {
return Ok(WakeupCause::Reset(ResetCause::External));
} else if reset_cause.is_watchdog() {
return Ok(WakeupCause::Reset(ResetCause::WatchDog));
}
}
Err(CauseError::InvalidCause)
}
unsafe fn store_backup<UD>(&self, user_data: &UD) -> Result<(), BackupError>
where
UD: Sized,
{
let backup = Backup::steal();
let ud_size = core::mem::size_of::<UD>();
if ud_size > BACKUP_LEN * BACKUP_REGISTER_BYTES {
return Err(BackupError::DataTooLarge);
}
if ud_size % BACKUP_REGISTER_BYTES != 0 {
return Err(BackupError::DataSizeInvalid);
}
let reg_count = ud_size / BACKUP_REGISTER_BYTES;
let ptr = user_data as *const _;
let ptr_u32 = ptr as *const u32;
let sliced = core::slice::from_raw_parts(ptr_u32, reg_count);
backup.backup_iter().enumerate().for_each(|(i, backup_r)| {
backup_r.write(|w| w.bits(sliced[i]));
});
Ok(())
}
unsafe fn restore_backup<UD>(&self, user_data: &mut UD) -> Result<(), BackupError>
where
UD: Sized,
{
let backup = Backup::steal();
let ud_size = core::mem::size_of::<UD>();
if ud_size > BACKUP_LEN * BACKUP_REGISTER_BYTES {
return Err(BackupError::DataTooLarge);
}
if ud_size % BACKUP_REGISTER_BYTES != 0 {
return Err(BackupError::DataSizeInvalid);
}
let reg_count = ud_size / BACKUP_REGISTER_BYTES;
let ptr = user_data as *const _;
let ptr_u32 = ptr as *mut u32;
let sliced = core::slice::from_raw_parts_mut(ptr_u32, reg_count);
backup.backup_iter().enumerate().for_each(|(i, backup_r)| {
sliced[i] = backup_r.read().bits();
});
Ok(())
}
fn clear_backup(&self) {
unsafe {
let backup = Backup::steal();
for backup_r in backup.backup_iter() {
backup_r.write(|w| w.bits(0u32));
}
}
}
}