diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a0e3d..08a2d06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - `flipperzero::dialogs::DialogFileBrowserOptions` +- `flipperzero::furi::kernel` module exposing most `furi_kernel_*` APIs ### Changed diff --git a/crates/flipperzero/src/furi/kernel.rs b/crates/flipperzero/src/furi/kernel.rs new file mode 100644 index 0000000..d8dfafe --- /dev/null +++ b/crates/flipperzero/src/furi/kernel.rs @@ -0,0 +1,90 @@ +//! Furi Kernel primitives. + +use flipperzero_sys as sys; +use ufmt::derive::uDebug; + +use crate::furi; + +/// Check if CPU is in IRQ; or kernel running and IRQ is masked. +pub fn is_irq_or_masked() -> bool { + unsafe { sys::furi_kernel_is_irq_or_masked() } +} + +/// Check if kernel is running. +pub fn is_running() -> bool { + unsafe { sys::furi_kernel_is_running() } +} + +/// Kernel lock state. +#[derive(Clone, Copy, Debug, PartialEq, Eq, uDebug)] +pub enum LockState { + /// normal scheduling + Unlocked = 0, + /// scheduling paused + Locked = 1, +} + +impl From for LockState { + fn from(value: i32) -> Self { + match value { + 0 => LockState::Unlocked, + // Assume any non-zero value is `Locked``. + // This can be modified if new lock states are added in the future. + _ => LockState::Locked, + } + } +} + +impl From for i32 { + fn from(value: LockState) -> Self { + value as i32 + } +} + +/// Lock kernel, pause process scheduling. +/// +///
This should never be called in an interrupt request context.
+/// +/// Returns previous lock state. +pub fn lock() -> furi::Result { + let status = sys::furi::Status::from(unsafe { sys::furi_kernel_lock() }); + + status.err_or_else(|status| status.0.into()) +} + +/// Unlock kernel, resume process scheduling. +/// +///
This should never be called in an interrupt request context.
+/// +/// Returns previous lock state. +pub fn unlock() -> furi::Result { + let status = sys::furi::Status::from(unsafe { sys::furi_kernel_unlock() }); + + status.err_or_else(|status| status.0.into()) +} + +/// Restore kernel lock state. +/// +///
This should never be called in an interrupt request context.
+/// +/// Returns previous lock state. +pub fn restore_lock(state: LockState) -> furi::Result { + let status = sys::furi::Status::from(unsafe { sys::furi_kernel_restore_lock(state.into()) }); + + status.err_or_else(|status| status.0.into()) +} + +/// Return kernel tick frequency in hertz. +#[inline] +pub fn get_tick_frequency() -> u32 { + unsafe { sys::furi_kernel_get_tick_frequency() } +} + +/// Return current kernel tick value. +/// +/// The duration of a tick depends on kernel configuration. +/// The value can be discovered with [`get_tick_frequency`]. +#[inline] +pub fn get_tick() -> u32 { + unsafe { sys::furi_get_tick() } +} diff --git a/crates/flipperzero/src/furi/mod.rs b/crates/flipperzero/src/furi/mod.rs index e14d0ad..98fcbb7 100644 --- a/crates/flipperzero/src/furi/mod.rs +++ b/crates/flipperzero/src/furi/mod.rs @@ -1,6 +1,7 @@ //! Furi API. pub mod io; +pub mod kernel; pub mod log; pub mod message_queue; pub mod rng; diff --git a/crates/flipperzero/src/furi/time.rs b/crates/flipperzero/src/furi/time.rs index c4c72f3..843eefd 100644 --- a/crates/flipperzero/src/furi/time.rs +++ b/crates/flipperzero/src/furi/time.rs @@ -2,9 +2,10 @@ use core::cmp::Ordering; use core::iter::Sum; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; -use flipperzero_sys as sys; use ufmt::derive::uDebug; +use crate::furi; + /// Maximum number of ticks a [`Duration`] can contain to be usable with [`Instant`]. const MAX_INTERVAL_DURATION_TICKS: u32 = u32::MAX / 2; @@ -16,7 +17,7 @@ const MILLIS_PER_SEC: u32 = 1_000; /// Converts the given number of nanoseconds to ticks. fn ns_to_ticks(nanos: u64) -> u64 { - let rate = unsafe { sys::furi_kernel_get_tick_frequency() }; + let rate = furi::kernel::get_tick_frequency(); if rate == MILLIS_PER_SEC { // This can be up to around 2^45 ticks. nanos / NANOS_PER_MILLI @@ -31,7 +32,7 @@ fn ns_to_ticks(nanos: u64) -> u64 { /// /// The upper 2 bits of the return value will always be zero. fn ticks_to_ns(ticks: u32) -> u64 { - let rate = unsafe { sys::furi_kernel_get_tick_frequency() }; + let rate = furi::kernel::get_tick_frequency(); if rate == MILLIS_PER_SEC { // This can be up to around 2^52 nanoseconds. (ticks as u64) * NANOS_PER_MILLI @@ -49,7 +50,7 @@ impl Instant { /// Returns an instant corresponding to "now". #[must_use] pub fn now() -> Instant { - Instant(unsafe { sys::furi_get_tick() }) + Instant(furi::kernel::get_tick()) } /// Returns the amount of time elapsed from another instant to this one.