ove/
timer.rs

1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! Software timer for oveRTOS.
8//!
9//! [`Timer`] wraps an RTOS software timer with a safe Rust `fn()` callback.
10//! Timers can be periodic or one-shot and are driven by the RTOS tick.
11
12use core::fmt;
13
14use crate::bindings;
15use crate::error::{Error, Result};
16
17/// Software timer with a safe Rust callback.
18///
19/// The timer stores a function pointer and generates an internal trampoline
20/// so the user callback is a plain `fn()` — no `unsafe`, no raw pointers.
21pub struct Timer {
22    handle: bindings::ove_timer_t,
23}
24
25impl Timer {
26    /// Create a new timer via heap allocation (only in heap mode).
27    ///
28    /// - `callback` — safe Rust function called each time the timer fires.
29    /// - `period_ms` — timer period in milliseconds.
30    /// - `one_shot` — if `true`, the timer fires once and stops.
31    #[cfg(not(zero_heap))]
32    pub fn new(callback: fn(), period_ms: u32, one_shot: bool) -> Result<Self> {
33        // Store the callback as the user_data pointer. On platforms where
34        // fn() is pointer-sized this is a direct cast; the trampoline
35        // reconverts it.
36        let user_data = callback as *mut core::ffi::c_void;
37
38        let mut handle: bindings::ove_timer_t = core::ptr::null_mut();
39        let rc = unsafe {
40            bindings::ove_timer_create(
41                &mut handle,
42                Some(Self::trampoline),
43                user_data,
44                period_ms,
45                one_shot as i32,
46            )
47        };
48        Error::from_code(rc)?;
49        Ok(Self { handle })
50    }
51
52    /// Create from caller-provided static storage.
53    ///
54    /// # Safety
55    /// Caller must ensure `storage` outlives the `Timer`.
56    #[cfg(zero_heap)]
57    pub unsafe fn from_static(
58        storage: *mut bindings::ove_timer_storage_t,
59        callback: fn(),
60        period_ms: u32,
61        one_shot: bool,
62    ) -> Result<Self> {
63        let user_data = callback as *mut core::ffi::c_void;
64        let mut handle: bindings::ove_timer_t = core::ptr::null_mut();
65        let rc = unsafe {
66            bindings::ove_timer_init(
67                &mut handle,
68                storage,
69                Some(Self::trampoline),
70                user_data,
71                period_ms,
72                one_shot as i32,
73            )
74        };
75        Error::from_code(rc)?;
76        Ok(Self { handle })
77    }
78
79    /// Start the timer, beginning countdown from now.
80    ///
81    /// # Errors
82    /// Returns an error if the underlying RTOS call fails.
83    pub fn start(&self) -> Result<()> {
84        let rc = unsafe { bindings::ove_timer_start(self.handle) };
85        Error::from_code(rc)
86    }
87
88    /// Stop the timer, preventing further callbacks until restarted.
89    ///
90    /// # Errors
91    /// Returns an error if the underlying RTOS call fails.
92    pub fn stop(&self) -> Result<()> {
93        let rc = unsafe { bindings::ove_timer_stop(self.handle) };
94        Error::from_code(rc)
95    }
96
97    /// Reset the timer, restarting the period from now.
98    ///
99    /// If the timer is stopped, this also starts it.
100    ///
101    /// # Errors
102    /// Returns an error if the underlying RTOS call fails.
103    pub fn reset(&self) -> Result<()> {
104        let rc = unsafe { bindings::ove_timer_reset(self.handle) };
105        Error::from_code(rc)
106    }
107
108    /// Internal trampoline that converts the C callback into a safe Rust call.
109    unsafe extern "C" fn trampoline(
110        _timer: bindings::ove_timer_t,
111        user_data: *mut core::ffi::c_void,
112    ) {
113        let cb: fn() = unsafe { core::mem::transmute(user_data) };
114        cb();
115    }
116}
117
118impl fmt::Debug for Timer {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        f.debug_struct("Timer")
121            .field("handle", &format_args!("{:p}", self.handle))
122            .finish()
123    }
124}
125
126impl Drop for Timer {
127    fn drop(&mut self) {
128        if self.handle.is_null() { return; }
129        #[cfg(not(zero_heap))]
130        unsafe { bindings::ove_timer_destroy(self.handle) }
131        #[cfg(zero_heap)]
132        unsafe { bindings::ove_timer_deinit(self.handle) }
133    }
134}
135
136// SAFETY: Timer wraps a ove_timer_t handle. Start/stop/reset are
137// thread-safe RTOS calls. Create/destroy are single-threaded (lifecycle
138// guarantee).
139unsafe impl Send for Timer {}
140unsafe impl Sync for Timer {}