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 {}