Skip to main content

esp_idf_hal/
timer.rs

1//! Timer driver for the [Timer Group peripheral].
2//!
3//! This timer can select different clock sources and prescalers to meet the requirements
4//! of nanosecond-level resolution. Additionally, it has flexible timeout alarm functions
5//! and allows automatic updating of the count value at the alarm moment,
6//! achieving very precise timing cycles.
7//!
8//! Based on the high resolution, high count range, and high response capabilities of the
9//! hardware timer, the main application scenarios of this driver include:
10//! - Running freely as a calendar clock to provide timestamp services for other modules
11//! - Generating periodic alarms to complete periodic tasks
12//! - Generating one-shot alarms, which can be used to implement a monotonic software timer list
13//!   with asynchronous updates of alarm values
14//! - Working with the GPIO module to achieve PWM signal output and input capture
15//! - ...
16//!
17//! [Timer Group peripheral]: https://documentation.espressif.com/esp32_technical_reference_manual_en.pdf#timg
18//!
19//! # Driver redesign in ESP-IDF 5.0
20//!
21//! In ESP-IDF 5.0, the [timer API was redesigned] to simplify and unify the usage of
22//! general purpose timer.
23//!
24//! It is recommended to use the new API, but for now the old API is available through
25//! the `timer-legacy` feature. The ESP-IDF 6.0 release will remove support for the legacy API.
26//!
27//! [timer API was redesigned]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/5.0/peripherals.html#timer-group-driver
28//!
29//! # Force enabling debug logs
30//!
31//! The `CONFIG_GPTIMER_ENABLE_DEBUG_LOG` option in the `sdkconfig` forces the
32//! GPTimer driver to enable all debug logs, regardless of the global log level settings.
33//! Enabling this option helps developers obtain more detailed log information during
34//! debugging, making it easier to locate and solve problems.
35use core::ffi::c_void;
36use core::time::Duration;
37use core::{fmt, ptr};
38
39use alloc::boxed::Box;
40
41use esp_idf_sys::*;
42
43use crate::interrupt;
44use crate::interrupt::asynch::HalIsrNotification;
45use crate::units::{FromValueType, Hertz};
46use config::*;
47
48/// This might not always be available in the generated `esp-idf-sys` bindings,
49/// which is why it is defined here.
50pub const ERR_EOVERFLOW: esp_err_t = 139;
51
52/// GPTimer alarm event data.
53#[derive(Debug, Clone, PartialEq, Eq)]
54#[non_exhaustive]
55pub struct AlarmEventData {
56    /// Current count value
57    pub count_value: u64,
58    /// Current alarm value
59    pub alarm_value: u64,
60}
61
62impl From<gptimer_alarm_event_data_t> for AlarmEventData {
63    fn from(value: gptimer_alarm_event_data_t) -> Self {
64        Self {
65            count_value: value.count_value,
66            alarm_value: value.alarm_value,
67        }
68    }
69}
70
71/// Timer configuration
72pub mod config {
73    use esp_idf_sys::*;
74
75    use crate::units::{FromValueType, Hertz};
76
77    /// GPTimer count direction
78    #[derive(Debug, Clone, Default)]
79    #[non_exhaustive]
80    pub enum CountDirection {
81        /// Decrease count value
82        #[default]
83        Up,
84        /// Increase count value
85        Down,
86    }
87
88    impl From<CountDirection> for gptimer_count_direction_t {
89        fn from(value: CountDirection) -> Self {
90            match value {
91                CountDirection::Up => gptimer_count_direction_t_GPTIMER_COUNT_UP,
92                CountDirection::Down => gptimer_count_direction_t_GPTIMER_COUNT_DOWN,
93            }
94        }
95    }
96
97    /// Type of GPTimer clock source.
98    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
99    pub enum ClockSource {
100        /// Use the default clock source.
101        #[default]
102        Default,
103        /// Select `APB` as the source clock
104        #[cfg(any(esp32, esp32s2, esp32s3, esp32c3))]
105        APB,
106        /// Select `RC_FAST` as the source clock
107        #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2, esp32p4))]
108        RcFast,
109        /// Select `XTAL` as the source clock
110        #[cfg(any(
111            esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32p4
112        ))]
113        XTAL,
114        /// Select `PLL_F40M` as the source clock
115        #[cfg(esp32c2)]
116        PLLF40M,
117        /// Select `PLL_F48M` as the source clock
118        #[cfg(esp32h2)]
119        PLLF48M,
120        /// Select `PLL_F80M` as the source clock
121        #[cfg(any(esp32c5, esp32c6, esp32c61, esp32p4))]
122        PLLF80M,
123    }
124
125    impl From<ClockSource> for soc_periph_gptimer_clk_src_t {
126        fn from(clock: ClockSource) -> Self {
127            match clock {
128                ClockSource::Default => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_DEFAULT,
129                #[cfg(any(esp32, esp32s2, esp32s3, esp32c3))]
130                ClockSource::APB => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_APB,
131                #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2, esp32p4))]
132                ClockSource::RcFast => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_RC_FAST,
133                #[cfg(any(
134                    esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2,
135                    esp32p4
136                ))]
137                ClockSource::XTAL => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_XTAL,
138                #[cfg(esp32c2)]
139                ClockSource::PLLF40M => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_PLL_F40M,
140                #[cfg(esp32h2)]
141                ClockSource::PLLF48M => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_PLL_F48M,
142                #[cfg(any(esp32c5, esp32c6, esp32c61, esp32p4))]
143                ClockSource::PLLF80M => soc_periph_gptimer_clk_src_t_GPTIMER_CLK_SRC_PLL_F80M,
144            }
145        }
146    }
147
148    /// Configuration for [`TimerDriver`](super::TimerDriver)
149    #[derive(Debug, Clone)]
150    pub struct TimerConfig {
151        /// GPTimer clock source
152        pub clock_source: ClockSource,
153        /// Count direction
154        pub direction: CountDirection,
155        /// Counter resolution (working frequency) in Hz, hence,
156        /// the step size of each count tick equals to (1 / resolution_hz) seconds
157        pub resolution: Hertz,
158        /// GPTimer interrupt priority, if set to 0, the driver will try to allocate an interrupt
159        /// with a relative low priority (1,2,3)
160        #[cfg(esp_idf_version_at_least_5_1_2)]
161        #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_1_2)))]
162        pub intr_priority: i32,
163        /// If set true, the timer interrupt number can be shared with other peripherals
164        pub intr_shared: bool,
165        /// If set, driver allows the power domain to be powered off when system enters
166        /// sleep mode. This can save power, but at the expense of more RAM being consumed
167        /// to save register context.
168        #[cfg(esp_idf_version_at_least_5_4_0)]
169        #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_4_0)))]
170        pub allow_pd: bool,
171        // This field is intentionally hidden to prevent non-exhaustive pattern matching.
172        // You should only construct this struct using the `..Default::default()` pattern.
173        // If you use this field directly, your code might break in future versions.
174        #[doc(hidden)]
175        #[allow(dead_code)]
176        pub __internal: (),
177    }
178
179    impl Default for TimerConfig {
180        fn default() -> Self {
181            Self {
182                clock_source: Default::default(),
183                direction: Default::default(),
184                resolution: 1_000_000.Hz(), // 1 MHz
185                #[cfg(esp_idf_version_at_least_5_1_2)]
186                intr_priority: 0,
187                intr_shared: false,
188                #[cfg(esp_idf_version_at_least_5_4_0)]
189                allow_pd: false,
190                __internal: (),
191            }
192        }
193    }
194
195    /// General Purpose Timer alarm configuration.
196    #[derive(Debug, Clone)]
197    pub struct AlarmConfig {
198        /// Alarm reload count value, effect only when [`Self::auto_reload_on_alarm`] is set to true
199        pub reload_count: u64,
200        /// Alarm target count value
201        pub alarm_count: u64,
202        /// Reload the count value by hardware, immediately at the alarm event
203        pub auto_reload_on_alarm: bool,
204        // This field is intentionally hidden to prevent non-exhaustive pattern matching.
205        // You should only construct this struct using the `..Default::default()` pattern.
206        // If you use this field directly, your code might break in future versions.
207        #[doc(hidden)]
208        #[allow(dead_code)]
209        pub __internal: (),
210    }
211
212    impl Default for AlarmConfig {
213        fn default() -> Self {
214            Self {
215                reload_count: 0,
216                alarm_count: 1_000_000,
217                auto_reload_on_alarm: false,
218                __internal: (),
219            }
220        }
221    }
222
223    impl From<&AlarmConfig> for gptimer_alarm_config_t {
224        fn from(config: &AlarmConfig) -> Self {
225            gptimer_alarm_config_t {
226                alarm_count: config.alarm_count,
227                reload_count: config.reload_count,
228                flags: gptimer_alarm_config_t__bindgen_ty_1 {
229                    _bitfield_1: gptimer_alarm_config_t__bindgen_ty_1::new_bitfield_1(
230                        config.auto_reload_on_alarm as _,
231                    ),
232                    ..Default::default()
233                },
234            }
235        }
236    }
237}
238
239struct AlarmUserData<'d> {
240    on_alarm: Box<dyn FnMut(AlarmEventData) + Send + 'd>,
241    notif: HalIsrNotification,
242}
243
244/// General Purpose Timer driver.
245///
246/// You can use this driver to get notified when a certain amount of time has passed
247/// ([`TimerDriver::subscribe`]), or to measure time intervals ([`TimerDriver::get_raw_count`]).
248///
249/// The driver has the following states:
250/// - "init" state: After creation of the driver, or after calling [`TimerDriver::disable`].
251/// - "enable" state: After calling [`TimerDriver::enable`]. In this state, the timer is ready to be started,
252///   but the internal counter is not running yet.
253/// - "run" state: After calling [`TimerDriver::start`]. In this state, the internal counter is running.
254///   To stop the counter, call [`TimerDriver::stop`], which would transition back to "enable" state.
255pub struct TimerDriver<'d> {
256    handle: gptimer_handle_t,
257    on_alarm: Option<Box<AlarmUserData<'d>>>,
258}
259
260impl<'d> TimerDriver<'d> {
261    /// Create a new General Purpose Timer, and return the handle.
262    ///
263    /// The state of the returned timer will be "init" state.
264    ///
265    /// # Errors
266    ///
267    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument
268    /// - `ESP_ERR_NO_MEM`: Failed because out of memory
269    /// - `ESP_ERR_NOT_FOUND`: Failed because all hardware timers are used up and no more free one
270    /// - `ESP_FAIL`: Failed because of other error
271    pub fn new(config: &TimerConfig) -> Result<Self, EspError> {
272        let sys_config = gptimer_config_t {
273            clk_src: config.clock_source.into(),
274            direction: config.direction.clone().into(),
275            resolution_hz: config.resolution.into(),
276            #[cfg(esp_idf_version_at_least_5_1_2)]
277            intr_priority: config.intr_priority,
278            flags: gptimer_config_t__bindgen_ty_1 {
279                _bitfield_1: gptimer_config_t__bindgen_ty_1::new_bitfield_1(
280                    config.intr_shared as _,
281                    #[cfg(esp_idf_version_at_least_5_4_0)]
282                    {
283                        config.allow_pd as _
284                    },
285                    // The `backup_before_sleep` field is deprecated, and will be removed in 6.1
286                    #[cfg(all(
287                        esp_idf_version_at_least_5_3_0,
288                        not(esp_idf_version_at_least_6_1_0)
289                    ))]
290                    {
291                        false as _
292                    },
293                ),
294                ..Default::default()
295            },
296        };
297        let mut handle = ptr::null_mut();
298
299        esp!(unsafe { gptimer_new_timer(&sys_config, &raw mut handle) })?;
300
301        Ok(Self {
302            handle,
303            on_alarm: None,
304        })
305    }
306
307    /// Returns the underlying GPTimer handle.
308    pub fn handle(&self) -> gptimer_handle_t {
309        self.handle
310    }
311
312    /// Converts the given duration to the corresponding timer count value.
313    ///
314    /// # Errors
315    ///
316    /// If [`Self::get_resolution`] fails, this function will return the same error.
317    ///
318    /// This function might overflow if the duration is too long to be represented
319    /// as ticks with the current timer resolution.
320    /// In that case an error with the code [`ERR_EOVERFLOW`] will be returned.
321    #[cfg(esp_idf_version_at_least_5_1_0)]
322    #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_1_0)))]
323    pub fn duration_to_count(&self, duration: Duration) -> Result<u64, EspError> {
324        // 1 / resolution = how many seconds per tick
325        // -> duration / (1 / resolution) = duration * resolution = how many ticks in duration (where duration is in seconds)
326        //
327        // The below calculation splits the duration into full seconds and the remainder in nanoseconds.
328        // The full seconds can simply be multiplied by the ticks per second (resolution).
329        //
330        // The remainder in nanoseconds would have to be converted to seconds to multiply with the resolution,
331        // but with whole numbers that would round down to zero (remainder is less than a full second).
332        // Therefore instead of:
333        // ticks += resolution * (duration_rem_in_nanos / 1_000_000_000)
334        // we do:
335        // ticks += (resolution * duration_rem_in_nanos) / 1_000_000_000
336        //
337        // The 1_000_000_000 is one second in nanoseconds.
338
339        let ticks_per_second = self.get_resolution()?.0 as u64;
340        let duration_in_seconds = duration.as_secs();
341        let duration_rem_in_nanos = duration.subsec_nanos() as u64;
342
343        let Some(ticks) = ticks_per_second.checked_mul(duration_in_seconds) else {
344            return Err(EspError::from_infallible::<ERR_EOVERFLOW>());
345        };
346
347        ticks
348            .checked_add(
349                (ticks_per_second * duration_rem_in_nanos)
350                    / Duration::from_secs(1).as_nanos() as u64,
351            )
352            .ok_or(EspError::from_infallible::<ERR_EOVERFLOW>())
353    }
354
355    /// Asynchronously delay for the specified duration.
356    ///
357    /// This function will reset the timer count to 0, and set a one-shot alarm.
358    /// Any existing count or alarm configuration will be overwritten.
359    /// This function does **not** [`Self::start`] or [`Self::enable`] the timer,
360    /// this must be done beforehand.
361    ///
362    /// # Errors
363    ///
364    /// If there is no interrupt service registered, it will return an `ESP_ERR_INVALID_STATE`.
365    /// To enable interrupts, either register your own callback through
366    /// [`Self::subscribe`]/[`Self::subscribe_nonstatic`], or call [`Self::subscribe_default`].
367    #[cfg(esp_idf_version_at_least_5_1_0)]
368    #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_1_0)))]
369    pub async fn delay(&self, duration: Duration) -> Result<(), EspError> {
370        let alarm_count = self.duration_to_count(duration)?;
371
372        // Set alarm and reset the current count to 0
373        self.set_raw_count(0)?;
374        self.set_alarm_action(Some(&AlarmConfig {
375            alarm_count,
376            ..Default::default()
377        }))?;
378
379        let res = self.wait().await;
380
381        // Unset the previous alarm
382        self.set_alarm_action(None)?;
383
384        res
385    }
386
387    fn notif(&self) -> Result<&HalIsrNotification, EspError> {
388        self.on_alarm
389            .as_ref()
390            .map(|data| &data.notif)
391            .ok_or(EspError::from_infallible::<ESP_ERR_INVALID_STATE>())
392    }
393
394    /// Wait for the timer alarm event interrupt.
395    ///
396    /// # Errors
397    ///
398    /// If this function is called without a registered ISR, it will
399    /// return an `ESP_ERR_INVALID_STATE`.
400    /// To enable interrupts, either register your own callback through
401    /// [`Self::subscribe`]/[`Self::subscribe_nonstatic`], or call [`Self::subscribe_default`].
402    pub async fn wait(&self) -> Result<(), EspError> {
403        self.notif()?.wait().await;
404
405        Ok(())
406    }
407
408    /// Resets the internal wait notification.
409    ///
410    /// If no callback is registered, this function does nothing.
411    pub fn reset_wait(&self) {
412        if let Ok(notif) = self.notif() {
413            notif.reset();
414        }
415    }
416
417    /// Set GPTimer raw count value.
418    ///
419    /// When updating the raw count of an active timer, the timer will
420    /// immediately start counting from the new value.
421    ///
422    /// # Errors
423    ///
424    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument
425    /// - `ESP_FAIL`: Failed because of other error
426    pub fn set_raw_count(&self, value: u64) -> Result<(), EspError> {
427        esp!(unsafe { gptimer_set_raw_count(self.handle, value) })
428    }
429
430    /// Get GPTimer raw count value.
431    ///
432    /// This function will trigger a software capture event and then return the captured count value.
433    ///
434    /// With the raw count value and the resolution returned from [`Self::get_resolution`], you can
435    /// convert the count value into seconds.
436    ///
437    /// # Errors
438    ///
439    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
440    /// - `ESP_FAIL`: Failed because of other error
441    pub fn get_raw_count(&self) -> Result<u64, EspError> {
442        let mut value: u64 = 0;
443        esp!(unsafe { gptimer_get_raw_count(self.handle, &raw mut value) })?;
444        Ok(value)
445    }
446
447    /// Return the real resolution of the timer.
448    ///
449    /// Usually the timer resolution is same as what you configured in the [`TimerConfig::resolution`],
450    /// but some unstable clock source (e.g. `RC_FAST`) will do a calibration, the real resolution can
451    /// be different from the configured one.
452    ///
453    /// # Errors
454    ///
455    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
456    /// - `ESP_FAIL`: Failed because of other error
457    #[cfg(esp_idf_version_at_least_5_1_0)]
458    #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_1_0)))]
459    pub fn get_resolution(&self) -> Result<Hertz, EspError> {
460        let mut value: u32 = 0;
461        esp!(unsafe { gptimer_get_resolution(self.handle, &raw mut value) })?;
462        Ok(value.Hz())
463    }
464
465    /// Get GPTimer captured count value.
466    ///
467    /// Different from [`Self::get_raw_count`], this function won't trigger a software capture event.
468    /// It just returns the last captured count value. It's especially useful when the capture has
469    /// already been triggered by an external event and you want to read the captured value.
470    ///
471    /// # Errors
472    ///
473    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
474    /// - `ESP_FAIL`: Failed because of other error
475    #[cfg(esp_idf_version_at_least_5_1_0)]
476    #[cfg_attr(feature = "nightly", doc(cfg(esp_idf_version_at_least_5_1_0)))]
477    pub fn get_captured_count(&self) -> Result<u64, EspError> {
478        let mut value: u64 = 0;
479        esp!(unsafe { gptimer_get_captured_count(self.handle, &raw mut value) })?;
480        Ok(value)
481    }
482
483    /// Define the ISR handler for when the alarm event occurs.
484    ///
485    /// The callbacks are expected to run in ISR context.
486    /// The first call to this function should happen before the timer is enabled
487    /// through [`Self::enable`].
488    ///
489    /// There is only one callback possible, you can not subscribe multiple callbacks.
490    ///
491    /// # ISR Safety
492    ///
493    /// Care should be taken not to call std, libc or FreeRTOS APIs (except for a few allowed ones)
494    /// in the callback passed to this function, as it is executed in an ISR context.
495    ///
496    /// You are not allowed to block, but you are allowed to call FreeRTOS APIs with the FromISR suffix.
497    ///
498    /// # Errors
499    ///
500    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument
501    /// - `ESP_ERR_INVALID_STATE`: Failed because the timer is not in init state
502    /// - `ESP_FAIL`: Failed because of other error
503    pub fn subscribe(
504        &mut self,
505        on_alarm: impl FnMut(AlarmEventData) + Send + 'static,
506    ) -> Result<(), EspError> {
507        unsafe { self.subscribe_nonstatic(on_alarm) }
508    }
509
510    /// Subscribe a non-'static callback for when a transmission is done.
511    ///
512    /// # Safety
513    ///
514    /// You must not forget the driver (for example through [`core::mem::forget`]), while the callback
515    /// is still subscribed, otherwise this would lead to undefined behavior.
516    ///
517    /// To unsubscribe the callback, call [`Self::unsubscribe`].
518    pub unsafe fn subscribe_nonstatic(
519        &mut self,
520        on_alarm: impl FnMut(AlarmEventData) + Send + 'd,
521    ) -> Result<(), EspError> {
522        let mut user_data = Box::new(AlarmUserData {
523            on_alarm: Box::new(on_alarm),
524            notif: HalIsrNotification::new(),
525        });
526        let cbs = gptimer_event_callbacks_t {
527            on_alarm: Some(Self::handle_isr),
528        };
529
530        esp!(unsafe {
531            gptimer_register_event_callbacks(self.handle, &cbs, (&raw mut *user_data) as *mut _)
532        })?;
533
534        // Store the user data in the struct to prevent it from being freed too early
535        self.on_alarm = Some(user_data);
536
537        Ok(())
538    }
539
540    /// Register the default callback.
541    ///
542    /// This function will overwrite any previously registered callbacks.
543    /// This is useful if you want to asynchronously wait for an alarm event
544    /// through [`Self::wait`] or [`Self::delay`].
545    pub fn subscribe_default(&mut self) -> Result<(), EspError> {
546        self.subscribe(|_| {})
547    }
548
549    /// Unregister the previously registered callback.
550    pub fn unsubscribe(&mut self) -> Result<(), EspError> {
551        esp!(unsafe {
552            gptimer_register_event_callbacks(self.handle, ptr::null(), ptr::null_mut())
553        })?;
554        self.on_alarm = None;
555
556        Ok(())
557    }
558
559    /// Set alarm event actions for GPTimer.
560    ///
561    /// If the config is `None`, the alarm will be disabled.
562    ///
563    /// # Errors
564    ///
565    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
566    /// - `ESP_FAIL`: Failed because of other error
567    pub fn set_alarm_action(&self, config: Option<&AlarmConfig>) -> Result<(), EspError> {
568        let sys_config = config.map(|c| c.into());
569
570        esp!(unsafe {
571            gptimer_set_alarm_action(self.handle, sys_config.as_ref().map_or(ptr::null(), |c| c))
572        })
573    }
574
575    /// Enable the timer.
576    ///
577    /// This function will transition the timer from the "init" state to "enable" state.
578    ///
579    /// # Note
580    ///
581    /// This function will enable the interrupt service, if a callback has been registered
582    /// through [`Self::subscribe`].
583    ///
584    /// It will acquire a power management lock, if a specific source clock (e.g. APB) is selected
585    /// in the timer configuration, while `CONFIG_PM_ENABLE` is set in the project configuration.
586    ///
587    /// To make the timer start counting, call [`Self::start`].
588    ///
589    /// # Errors
590    ///
591    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
592    /// - `ESP_ERR_INVALID_STATE`: Failed because the timer is not in "init" state (e.g. already enabled)
593    /// - `ESP_FAIL`: Failed because of other error
594    pub fn enable(&self) -> Result<(), EspError> {
595        esp!(unsafe { gptimer_enable(self.handle) })
596    }
597
598    /// Disable the timer.
599    ///
600    /// This function will transition the timer from the "enable" state to "init" state.
601    ///
602    /// # Note
603    ///
604    /// This function will disable the interrupt service, if a callback has been registered
605    /// through [`Self::subscribe`].
606    ///
607    /// It will release the power management lock, if it acquired one in [`Self::enable`].
608    ///
609    /// Disabling the timer will not make it stop counting.
610    /// To make the timer stop counting, call [`Self::stop`].
611    ///
612    /// # Errors
613    ///
614    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
615    /// - `ESP_ERR_INVALID_STATE`: Failed because the timer is not in "enable" state (e.g. already disabled)
616    /// - `ESP_FAIL`: Failed because of other error
617    pub fn disable(&self) -> Result<(), EspError> {
618        esp!(unsafe { gptimer_disable(self.handle) })
619    }
620
621    /// Start GPTimer (internal counter starts counting)
622    ///
623    /// This function will transition the timer from the "enable" state to "run" state.
624    ///
625    /// # Errors
626    ///
627    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
628    /// - `ESP_ERR_INVALID_STATE`: Failed because the timer is not enabled or already in running
629    /// - `ESP_FAIL`: Failed because of other error
630    pub fn start(&self) -> Result<(), EspError> {
631        esp!(unsafe { gptimer_start(self.handle) })
632    }
633
634    /// Stop GPTimer (internal counter stops counting)
635    ///
636    /// This function will transition the timer from the "run" state to "enable" state.
637    ///
638    /// # Errors
639    ///
640    /// - `ESP_ERR_INVALID_ARG`: Failed because of invalid argument (should not happen)
641    /// - `ESP_ERR_INVALID_STATE`: Failed because the timer is not in running.
642    /// - `ESP_FAIL`: Failed because of other error
643    pub fn stop(&self) -> Result<(), EspError> {
644        esp!(unsafe { gptimer_stop(self.handle) })
645    }
646
647    unsafe extern "C" fn handle_isr(
648        _handle: gptimer_handle_t,
649        event_data: *const gptimer_alarm_event_data_t,
650        arg: *mut c_void,
651    ) -> bool {
652        let user_data = &mut *(arg as *mut AlarmUserData);
653        let event = AlarmEventData::from(*event_data);
654
655        interrupt::with_isr_yield_signal(|| {
656            (user_data.on_alarm)(event);
657
658            user_data.notif.notify_lsb();
659        })
660    }
661}
662
663// SAFETY: According to the ESP-IDF docs, the driver can be used in a multi-threaded context
664//         without extra locking.
665unsafe impl<'d> Send for TimerDriver<'d> {}
666unsafe impl<'d> Sync for TimerDriver<'d> {}
667
668impl<'d> Drop for TimerDriver<'d> {
669    fn drop(&mut self) {
670        // Timer must be from run -> enable state first before it is disabled
671        let _ = self.stop();
672        // Timer must be in "init" state before deletion (= disable state)
673        let _ = self.disable();
674
675        unsafe {
676            gptimer_del_timer(self.handle);
677        }
678    }
679}
680
681impl<'d> fmt::Debug for TimerDriver<'d> {
682    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683        f.debug_struct("TimerDriver")
684            .field("handle", &self.handle)
685            .finish()
686    }
687}