1use core::time::Duration;
43
44use esp_idf_sys::*;
45
46pub use esp_idf_sys::TickType_t;
48
49pub const BLOCK: TickType_t = TickType_t::MAX;
54
55pub const NON_BLOCK: TickType_t = 0;
57
58pub const TICK_RATE_HZ: u32 = configTICK_RATE_HZ;
61
62const MS_PER_S: u64 = 1_000;
63const NS_PER_MS: u64 = 1_000_000;
64const US_PER_MS: u32 = 1_000;
65const NS_PER_US: u32 = 1_000;
66
67#[inline]
68const fn const_min_u64(a: u64, b: u64) -> u64 {
69 if a < b {
70 a
71 } else {
72 b
73 }
74}
75
76#[repr(transparent)]
78pub struct TickType(pub TickType_t);
79
80impl TickType {
81 #[inline]
83 pub const fn new(ticks: TickType_t) -> Self {
84 Self(ticks)
85 }
86
87 pub const fn new_millis(ms: u64) -> Self {
90 let ticks = ms
91 .saturating_mul(TICK_RATE_HZ as u64)
92 .saturating_add(MS_PER_S - 1)
93 / MS_PER_S;
94 Self(const_min_u64(ticks, TickType_t::MAX as _) as _)
95 }
96
97 #[inline]
99 pub const fn ticks(&self) -> TickType_t {
100 self.0
101 }
102
103 pub const fn as_millis(&self) -> u64 {
106 (self.0 as u64)
107 .saturating_mul(MS_PER_S)
108 .saturating_add(TICK_RATE_HZ as u64 - 1)
109 / TICK_RATE_HZ as u64
110 }
111
112 #[inline]
116 pub const fn as_millis_u32(&self) -> u32 {
117 const_min_u64(self.as_millis(), u32::MAX as _) as _
118 }
119}
120
121impl From<TickType_t> for TickType {
122 #[inline]
123 fn from(value: TickType_t) -> Self {
124 Self::new(value)
125 }
126}
127
128impl From<TickType> for TickType_t {
129 #[inline]
130 fn from(value: TickType) -> Self {
131 value.ticks()
132 }
133}
134
135impl From<Duration> for TickType {
136 fn from(duration: Duration) -> Self {
137 let sec_ms = duration.as_secs().saturating_mul(MS_PER_S);
138 let subsec_ns: u64 = duration.subsec_nanos().into();
139 let subsec_ms = subsec_ns.div_ceil(NS_PER_MS);
141
142 TickType::new_millis(sec_ms.saturating_add(subsec_ms))
143 }
144}
145
146impl From<Option<Duration>> for TickType {
147 fn from(duration: Option<Duration>) -> Self {
148 if let Some(duration) = duration {
149 duration.into()
150 } else {
151 TickType(BLOCK)
152 }
153 }
154}
155
156impl From<TickType> for Duration {
157 fn from(ticks: TickType) -> Self {
158 Duration::from_millis(ticks.as_millis())
159 }
160}
161
162impl From<TickType> for Option<Duration> {
163 fn from(ticks: TickType) -> Self {
164 if ticks.0 == BLOCK {
165 None
166 } else {
167 Some(ticks.into())
168 }
169 }
170}
171
172pub struct Ets;
180
181#[cfg(not(esp_idf_version_major = "4"))]
184extern "C" {
185 fn ets_delay_us(us: u32);
186}
187
188impl Ets {
189 #[inline]
192 pub fn delay_us(us: u32) {
193 unsafe {
194 ets_delay_us(us);
195 }
196 }
197
198 pub fn delay_ms(ms: u32) {
202 Self::delay_us(ms.saturating_mul(US_PER_MS));
203 }
204}
205
206impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for Ets {
207 #[inline]
208 fn delay_us(&mut self, us: u32) {
209 Ets::delay_us(us);
210 }
211}
212
213impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Ets {
214 #[inline]
215 fn delay_us(&mut self, us: u16) {
216 Ets::delay_us(us.into());
217 }
218}
219
220impl embedded_hal_0_2::blocking::delay::DelayUs<u8> for Ets {
221 #[inline]
222 fn delay_us(&mut self, us: u8) {
223 Ets::delay_us(us.into());
224 }
225}
226
227impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for Ets {
228 #[inline]
229 fn delay_ms(&mut self, ms: u32) {
230 Ets::delay_ms(ms);
231 }
232}
233
234impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for Ets {
235 #[inline]
236 fn delay_ms(&mut self, ms: u16) {
237 Ets::delay_ms(ms.into());
238 }
239}
240
241impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for Ets {
242 #[inline]
243 fn delay_ms(&mut self, ms: u8) {
244 Ets::delay_ms(ms.into());
245 }
246}
247
248impl embedded_hal::delay::DelayNs for Ets {
249 #[inline]
250 fn delay_ns(&mut self, ns: u32) {
251 Ets::delay_us(ns.saturating_add(NS_PER_US - 1) / NS_PER_US);
252 }
253
254 #[inline]
255 fn delay_us(&mut self, us: u32) {
256 Ets::delay_us(us);
257 }
258
259 #[inline]
260 fn delay_ms(&mut self, ms: u32) {
261 Ets::delay_ms(ms);
262 }
263}
264
265pub struct FreeRtos;
272
273impl FreeRtos {
274 pub fn delay_ms(ms: u32) {
277 let ticks = TickType::new_millis(ms.into()).ticks();
278 unsafe {
279 vTaskDelay(ticks);
280 }
281 }
282
283 fn delay_us(us: u32) {
287 Self::delay_ms(us.saturating_add(US_PER_MS - 1) / US_PER_MS);
288 }
289}
290
291impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for FreeRtos {
292 #[inline]
293 fn delay_us(&mut self, us: u32) {
294 FreeRtos::delay_us(us);
295 }
296}
297
298impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for FreeRtos {
299 #[inline]
300 fn delay_us(&mut self, us: u16) {
301 FreeRtos::delay_us(us.into());
302 }
303}
304
305impl embedded_hal_0_2::blocking::delay::DelayUs<u8> for FreeRtos {
306 #[inline]
307 fn delay_us(&mut self, us: u8) {
308 FreeRtos::delay_us(us.into());
309 }
310}
311
312impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for FreeRtos {
313 #[inline]
314 fn delay_ms(&mut self, ms: u32) {
315 FreeRtos::delay_ms(ms);
316 }
317}
318
319impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for FreeRtos {
320 #[inline]
321 fn delay_ms(&mut self, ms: u16) {
322 FreeRtos::delay_ms(ms.into());
323 }
324}
325
326impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for FreeRtos {
327 #[inline]
328 fn delay_ms(&mut self, ms: u8) {
329 FreeRtos::delay_ms(ms.into());
330 }
331}
332
333impl embedded_hal::delay::DelayNs for FreeRtos {
334 #[inline]
335 fn delay_ns(&mut self, ns: u32) {
336 FreeRtos::delay_us(ns.saturating_add(NS_PER_US - 1) / NS_PER_US);
337 }
338
339 #[inline]
340 fn delay_us(&mut self, us: u32) {
341 FreeRtos::delay_us(us);
342 }
343
344 #[inline]
345 fn delay_ms(&mut self, ms: u32) {
346 FreeRtos::delay_ms(ms);
347 }
348}
349
350#[derive(Copy, Clone)]
353pub struct Delay(u32);
354
355impl Delay {
356 #[inline]
358 pub const fn new_default() -> Self {
359 Self::new(1000)
360 }
361
362 #[inline]
364 pub const fn new(threshold_us: u32) -> Self {
365 Self(threshold_us)
366 }
367
368 #[inline]
371 pub fn delay_us(&self, us: u32) {
372 if us < self.0 {
373 Ets::delay_us(us);
374 } else {
375 FreeRtos::delay_us(us);
376 }
377 }
378
379 pub fn delay_ms(&self, ms: u32) {
382 if ms.saturating_mul(US_PER_MS) < self.0 {
383 Ets::delay_ms(ms);
384 } else {
385 FreeRtos::delay_ms(ms);
386 }
387 }
388}
389
390impl Default for Delay {
391 #[inline]
392 fn default() -> Self {
393 Self::new_default()
394 }
395}
396
397impl embedded_hal::delay::DelayNs for Delay {
398 #[inline]
399 fn delay_ns(&mut self, ns: u32) {
400 Delay::delay_us(self, ns.saturating_add(NS_PER_US - 1) / NS_PER_US)
401 }
402
403 #[inline]
404 fn delay_us(&mut self, us: u32) {
405 Delay::delay_us(self, us)
406 }
407
408 #[inline]
409 fn delay_ms(&mut self, ms: u32) {
410 Delay::delay_ms(self, ms)
411 }
412}
413
414impl embedded_hal_0_2::blocking::delay::DelayUs<u8> for Delay {
415 #[inline]
416 fn delay_us(&mut self, us: u8) {
417 Delay::delay_us(self, us.into());
418 }
419}
420
421impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Delay {
422 #[inline]
423 fn delay_us(&mut self, us: u16) {
424 Delay::delay_us(self, us.into());
425 }
426}
427
428impl embedded_hal_0_2::blocking::delay::DelayUs<u32> for Delay {
429 #[inline]
430 fn delay_us(&mut self, us: u32) {
431 Delay::delay_us(self, us);
432 }
433}
434
435impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for Delay {
436 #[inline]
437 fn delay_ms(&mut self, ms: u8) {
438 Delay::delay_ms(self, ms.into())
439 }
440}
441
442impl embedded_hal_0_2::blocking::delay::DelayMs<u16> for Delay {
443 #[inline]
444 fn delay_ms(&mut self, ms: u16) {
445 Delay::delay_ms(self, ms.into())
446 }
447}
448
449impl embedded_hal_0_2::blocking::delay::DelayMs<u32> for Delay {
450 #[inline]
451 fn delay_ms(&mut self, ms: u32) {
452 Delay::delay_ms(self, ms)
453 }
454}