use embedded_hal::delay::DelayNs;
use crate::regs::dma::{self, bus_mode, DMABUSMODE};
pub const SOFT_RESET_TIMEOUT_MS: u32 = 100;
pub const RESET_POLL_INTERVAL_US: u32 = 100;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ResetError {
Timeout,
}
pub struct ResetController<D: DelayNs> {
delay: D,
timeout_ms: u32,
}
impl<D: DelayNs> ResetController<D> {
pub fn new(delay: D) -> Self {
Self {
delay,
timeout_ms: SOFT_RESET_TIMEOUT_MS,
}
}
pub fn with_timeout(delay: D, timeout_ms: u32) -> Self {
Self { delay, timeout_ms }
}
pub fn soft_reset(&mut self) -> Result<(), ResetError> {
unsafe { dma::set_bits(DMABUSMODE, bus_mode::SW_RESET) };
let max_iters = (u64::from(self.timeout_ms) * 1000 / u64::from(RESET_POLL_INTERVAL_US))
.clamp(1, u64::from(u32::MAX)) as u32;
let mut iter = 0u32;
loop {
let still_in_progress = unsafe { dma::read(DMABUSMODE) } & bus_mode::SW_RESET != 0;
if !still_in_progress {
return Ok(());
}
iter += 1;
if iter >= max_iters {
return Err(ResetError::Timeout);
}
self.delay.delay_us(RESET_POLL_INTERVAL_US);
}
}
pub fn timeout_ms(&self) -> u32 {
self.timeout_ms
}
}
#[cfg(feature = "async")]
pub mod async_impl {
use embedded_hal_async::delay::DelayNs;
use super::{ResetError, RESET_POLL_INTERVAL_US, SOFT_RESET_TIMEOUT_MS};
use crate::regs::dma::{self, bus_mode, DMABUSMODE};
pub struct AsyncResetController<D: DelayNs> {
delay: D,
timeout_ms: u32,
}
impl<D: DelayNs> AsyncResetController<D> {
pub fn new(delay: D) -> Self {
Self {
delay,
timeout_ms: SOFT_RESET_TIMEOUT_MS,
}
}
pub fn with_timeout(delay: D, timeout_ms: u32) -> Self {
Self { delay, timeout_ms }
}
pub async fn soft_reset(&mut self) -> Result<(), ResetError> {
unsafe { dma::set_bits(DMABUSMODE, bus_mode::SW_RESET) };
let max_iters = (u64::from(self.timeout_ms) * 1000 / u64::from(RESET_POLL_INTERVAL_US))
.clamp(1, u64::from(u32::MAX)) as u32;
let mut iter = 0u32;
loop {
let still_in_progress = unsafe { dma::read(DMABUSMODE) } & bus_mode::SW_RESET != 0;
if !still_in_progress {
return Ok(());
}
iter += 1;
if iter >= max_iters {
return Err(ResetError::Timeout);
}
self.delay.delay_us(RESET_POLL_INTERVAL_US).await;
}
}
pub fn timeout_ms(&self) -> u32 {
self.timeout_ms
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
async fn _compile_check<D: DelayNs>(d: D) -> Result<(), ResetError> {
let mut ctl = AsyncResetController::with_timeout(d, 100);
ctl.soft_reset().await
}
}
}