diff --git a/src/lib.rs b/src/lib.rs index e57233e..589a199 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,15 @@ #![no_std] +use core::convert::TryFrom; use core::mem::MaybeUninit; use core::ptr; extern crate libc; +// avoid conflicting a real POSIX errno by using a value < 0 +// should we define this in ctru-sys somewhere or something? +const ECTRU: libc::c_int = -1; + /// Call this somewhere to force Rust to link this module. /// The call doesn't need to execute, just exist. /// @@ -51,6 +56,7 @@ unsafe extern "C" fn clock_gettime( tp: *mut libc::timespec, ) -> libc::c_int { let mut retval = -1; + match clock_id { libc::CLOCK_REALTIME => { let mut tv = MaybeUninit::uninit(); @@ -62,6 +68,24 @@ unsafe extern "C" fn clock_gettime( (*tp).tv_sec = tv.tv_sec; } } + libc::CLOCK_MONOTONIC => { + if let Ok(tick) = i64::try_from(ctru_sys::svcGetSystemTick()) { + retval = 0; + + let sysclock_rate = i64::from(ctru_sys::SYSCLOCK_ARM11); + (*tp).tv_sec = tick / sysclock_rate; + + // this should always fit in an f64 easily, since it's < sysclock_rate + let remainder = (tick % sysclock_rate) as f64; + + // cast to i32 rounds toward zero, which should be fine for this use case + (*tp).tv_nsec = (1000.0 * (remainder / ctru_sys::CPU_TICKS_PER_USEC)) as i32; + } else { + // Too many ticks, this device has been on for >1000 years! + // We would have otherwise given a negative result back to caller + *__errno() = ECTRU + } + } _ => *__errno() = libc::EINVAL, }