use core::time::Duration;
use esp_idf_sys::*;
use crate::units::Hertz;
const ERR_EOVERFLOW: esp_err_t = 139;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PinState {
Low,
High,
}
impl From<bool> for PinState {
fn from(state: bool) -> Self {
(state as u32).into()
}
}
impl From<u32> for PinState {
fn from(state: u32) -> Self {
if state == 0 {
Self::Low
} else {
Self::High
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Pulse {
pub ticks: PulseTicks,
pub pin_state: PinState,
}
impl Pulse {
pub const fn zero() -> Self {
Self::new(PinState::Low, PulseTicks::zero())
}
pub const fn new(pin_state: PinState, ticks: PulseTicks) -> Self {
Self { pin_state, ticks }
}
pub const fn new_with_duration(
resolution: Hertz,
pin_state: PinState,
duration: Duration,
) -> Result<Self, EspError> {
match PulseTicks::new_with_duration(resolution, duration) {
Ok(ticks) => Ok(Self::new(pin_state, ticks)),
Err(error) => Err(error),
}
}
}
impl Default for Pulse {
fn default() -> Self {
Self::zero()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
pub struct PulseTicks(u16);
impl PulseTicks {
const MAX: u16 = 32767;
pub const fn zero() -> Self {
Self(0)
}
pub const fn max() -> Self {
Self(Self::MAX)
}
pub const fn new(ticks: u16) -> Result<Self, EspError> {
if ticks > Self::MAX {
Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())
} else {
Ok(Self(ticks))
}
}
pub const fn new_with_duration(
resolution: Hertz,
duration: Duration,
) -> Result<Self, EspError> {
match duration_to_ticks(resolution, duration) {
Ok(ticks) => Self::new(ticks),
Err(error) => Err(error),
}
}
pub const fn ticks(&self) -> u16 {
self.0
}
pub const fn duration(&self, resolution: Hertz) -> Duration {
match ticks_to_duration(resolution, self.ticks()) {
Ok(duration) => duration,
Err(_) => panic!("Overflow while converting ticks to duration"),
}
}
}
const ONE_SECOND_IN_NANOS: u128 = Duration::from_secs(1).as_nanos();
pub const fn duration_to_ticks(resolution: Hertz, duration: Duration) -> Result<u16, EspError> {
let Some(ticks) = duration.as_nanos().checked_mul(resolution.0 as u128) else {
return Err(EspError::from_infallible::<ERR_EOVERFLOW>());
};
let ticks = ticks / ONE_SECOND_IN_NANOS;
if ticks > u16::MAX as u128 {
return Err(EspError::from_infallible::<ERR_EOVERFLOW>());
}
Ok(ticks as u16)
}
pub const fn ticks_to_duration(resolution: Hertz, ticks: u16) -> Result<Duration, EspError> {
let Some(duration) = ONE_SECOND_IN_NANOS.checked_mul(ticks as u128) else {
return Err(EspError::from_infallible::<ERR_EOVERFLOW>());
};
let duration = duration / resolution.0 as u128;
if duration > u64::MAX as u128 {
return Err(EspError::from_infallible::<ERR_EOVERFLOW>());
}
Ok(Duration::from_nanos(duration as u64))
}