use core::{cmp::min, time::Duration};
use esp_idf_sys::*;
#[allow(non_upper_case_globals)]
pub const BLOCK: TickType_t = TickType_t::MAX;
#[allow(non_upper_case_globals)]
pub const NON_BLOCK: TickType_t = 0;
#[allow(non_upper_case_globals)]
pub const TICK_PERIOD_MS: u32 = 1000 / configTICK_RATE_HZ;
#[repr(transparent)]
pub struct TickType(pub TickType_t);
impl TickType {
pub const fn new(ticks: TickType_t) -> Self {
Self(ticks)
}
pub const fn ticks(&self) -> TickType_t {
self.0
}
pub fn as_millis(&self) -> u64 {
self.0 as u64 * TICK_PERIOD_MS as u64
}
pub fn as_millis_u32(&self) -> u32 {
min(self.as_millis(), u32::MAX as _) as _
}
}
impl From<TickType_t> for TickType {
fn from(value: TickType_t) -> Self {
Self::new(value)
}
}
impl From<TickType> for TickType_t {
fn from(value: TickType) -> Self {
value.ticks()
}
}
impl From<Duration> for TickType {
fn from(duration: Duration) -> Self {
TickType(
((duration.as_millis() + TICK_PERIOD_MS as u128 - 1) / TICK_PERIOD_MS as u128)
as TickType_t,
)
}
}
impl From<Option<Duration>> for TickType {
fn from(duration: Option<Duration>) -> Self {
if let Some(duration) = duration {
duration.into()
} else {
TickType(BLOCK)
}
}
}
impl From<TickType> for Duration {
fn from(ticks: TickType) -> Self {
Duration::from_millis(ticks.0 as u64 * TICK_PERIOD_MS as u64)
}
}
impl From<TickType> for Option<Duration> {
fn from(ticks: TickType) -> Self {
if ticks.0 == BLOCK {
None
} else {
Some(ticks.into())
}
}
}
pub struct Ets;
#[cfg(not(esp_idf_version_major = "4"))]
extern "C" {
pub fn ets_delay_us(us: u32);
}
impl Ets {
pub fn delay_us(us: u32) {
unsafe {
ets_delay_us(us);
}
}
pub fn delay_ms(ms: u32) {
unsafe {
ets_delay_us(ms * 1000);
}
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for Ets {
fn delay_us(&mut self, us: u32) {
Ets::delay_us(us);
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Ets {
fn delay_us(&mut self, us: u16) {
Ets::delay_us(us as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u8> for Ets {
fn delay_us(&mut self, us: u8) {
Ets::delay_us(us as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for Ets {
fn delay_ms(&mut self, ms: u32) {
Ets::delay_ms(ms);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for Ets {
fn delay_ms(&mut self, ms: u16) {
Ets::delay_ms(ms as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for Ets {
fn delay_ms(&mut self, ms: u8) {
Ets::delay_ms(ms as _);
}
}
impl embedded_hal::delay::DelayUs for Ets {
fn delay_us(&mut self, us: u32) {
Ets::delay_us(us)
}
fn delay_ms(&mut self, ms: u32) {
Ets::delay_ms(ms)
}
}
pub struct FreeRtos;
impl FreeRtos {
pub fn delay_us(us: u32) {
let ms = us / 1000;
Self::delay_ms(ms);
}
pub fn delay_ms(ms: u32) {
let ticks = ms.saturating_add(TICK_PERIOD_MS - 1) / TICK_PERIOD_MS;
unsafe {
vTaskDelay(ticks);
}
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for FreeRtos {
fn delay_us(&mut self, us: u32) {
FreeRtos::delay_us(us);
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for FreeRtos {
fn delay_us(&mut self, us: u16) {
FreeRtos::delay_us(us as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u8> for FreeRtos {
fn delay_us(&mut self, us: u8) {
FreeRtos::delay_us(us as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for FreeRtos {
fn delay_ms(&mut self, ms: u32) {
FreeRtos::delay_ms(ms);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for FreeRtos {
fn delay_ms(&mut self, ms: u16) {
FreeRtos::delay_ms(ms as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for FreeRtos {
fn delay_ms(&mut self, ms: u8) {
FreeRtos::delay_ms(ms as _);
}
}
impl embedded_hal::delay::DelayUs for FreeRtos {
fn delay_us(&mut self, us: u32) {
FreeRtos::delay_us(us)
}
fn delay_ms(&mut self, ms: u32) {
FreeRtos::delay_ms(ms)
}
}
#[derive(Copy, Clone)]
pub struct Delay(u32);
impl Delay {
pub const fn new_default() -> Self {
Self::new(1000)
}
pub const fn new(threshold: u32) -> Self {
Self(threshold)
}
pub fn delay_us(&self, us: u32) {
if us < self.0 {
Ets::delay_us(us);
} else {
FreeRtos::delay_us(us);
}
}
pub fn delay_ms(&self, ms: u32) {
if ms * 1000 < self.0 {
Ets::delay_ms(ms);
} else {
FreeRtos::delay_ms(ms);
}
}
}
impl embedded_hal::delay::DelayUs for Delay {
fn delay_us(&mut self, us: u32) {
Delay::delay_us(self, us)
}
fn delay_ms(&mut self, ms: u32) {
Delay::delay_ms(self, ms)
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Delay {
fn delay_us(&mut self, us: u16) {
Delay::delay_us(self, us as _);
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for Delay {
fn delay_us(&mut self, us: u32) {
Delay::delay_us(self, us);
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for Delay {
fn delay_ms(&mut self, ms: u16) {
Delay::delay_ms(self, ms as _)
}
}
impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for Delay {
fn delay_ms(&mut self, ms: u32) {
Delay::delay_ms(self, ms)
}
}