|
| 1 | +use crate::{ |
| 2 | + clock::Clock, context::Context, error::RclrsError, rcl_bindings::*, to_rclrs_result |
| 3 | +}; |
| 4 | +use std::sync::{Arc, Mutex}; |
| 5 | + |
| 6 | + |
| 7 | +#[derive(Debug)] |
| 8 | +pub struct Timer { |
| 9 | + rcl_timer: Arc<Mutex<rcl_timer_t>>, |
| 10 | +} |
| 11 | + |
| 12 | +unsafe extern "C" fn timer_callback(_: *mut rcl_timer_t, time_since_last_callback_ns: i64) { |
| 13 | + println!("timer_callback, time_since_last_callback_ns {0}", time_since_last_callback_ns); |
| 14 | +} |
| 15 | + |
| 16 | +impl Timer { |
| 17 | + pub fn new(clock: &Clock, context: &Context, period: i64) -> Result<Timer, RclrsError> { |
| 18 | + let mut rcl_timer; |
| 19 | + let timer_init_result; |
| 20 | + unsafe { |
| 21 | + // SAFETY: Getting a default value is always safe. |
| 22 | + rcl_timer = rcl_get_zero_initialized_timer(); |
| 23 | + let allocator = rcutils_get_default_allocator(); |
| 24 | + let mut rcl_clock = clock.rcl_clock.lock().unwrap(); |
| 25 | + let mut rcl_context = context.handle.rcl_context.lock().unwrap(); |
| 26 | + let callback: rcl_timer_callback_t = Some(timer_callback); |
| 27 | + // Function will return Err(_) only if there isn't enough memory to allocate a clock |
| 28 | + // object. |
| 29 | + timer_init_result = rcl_timer_init( |
| 30 | + &mut rcl_timer, |
| 31 | + &mut *rcl_clock, |
| 32 | + &mut *rcl_context, |
| 33 | + period, |
| 34 | + callback, |
| 35 | + allocator, |
| 36 | + ); |
| 37 | + } |
| 38 | + to_rclrs_result(timer_init_result).map(|_| { |
| 39 | + Timer { |
| 40 | + rcl_timer: Arc::new(Mutex::new(rcl_timer)) |
| 41 | + } |
| 42 | + }) |
| 43 | + } |
| 44 | + |
| 45 | + // handle() -> RCLC Timer Type |
| 46 | + |
| 47 | + // destroy() -> None |
| 48 | + |
| 49 | + // clock() -> Clock ? |
| 50 | + |
| 51 | + // timer_period_ns -> i64 ? |
| 52 | + |
| 53 | + // is_ready() -> bool |
| 54 | + |
| 55 | + // is_cancelled() -> bool |
| 56 | + |
| 57 | + // cancel() -> None |
| 58 | + |
| 59 | + // reset() -> None |
| 60 | + |
| 61 | + // time_since_last_call() -> i64 |
| 62 | + |
| 63 | + // time_until_next_call() -> Option<i64> |
| 64 | + |
| 65 | +} |
| 66 | + |
| 67 | +impl Drop for rcl_timer_t { |
| 68 | + fn drop(&mut self) { |
| 69 | + // SAFETY: No preconditions for this function |
| 70 | + let rc = unsafe { rcl_timer_fini(&mut *self) }; |
| 71 | + if let Err(e) = to_rclrs_result(rc) { |
| 72 | + panic!("Unable to release Timer. {:?}", e) |
| 73 | + } |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread |
| 78 | +// they are running in. Therefore, this type can be safely sent to another thread. |
| 79 | +unsafe impl Send for rcl_timer_t {} |
| 80 | + |
| 81 | +#[cfg(test)] |
| 82 | +mod tests { |
| 83 | + use super::*; |
| 84 | + |
| 85 | + #[test] |
| 86 | + fn traits() { |
| 87 | + use crate::test_helpers::*; |
| 88 | + |
| 89 | + assert_send::<Timer>(); |
| 90 | + assert_sync::<Timer>(); |
| 91 | + } |
| 92 | +} |
0 commit comments