From 3e1a85660c5d7054848c5b3e5fd533d0287acdd3 Mon Sep 17 00:00:00 2001 From: David Coles Date: Sun, 20 Oct 2024 20:44:58 -0700 Subject: [PATCH] Add `flipperzero::furi::kernel` module This module exposes most of the `furi_kernel_*` APIs. Centralizing these lets us remove a number of `unsafe` calls peppered across the codebase and allows things like providing optimized versions. --- CHANGELOG.md | 1 + crates/flipperzero/src/furi/kernel.rs | 89 +++++++++++++++++++++++++++ crates/flipperzero/src/furi/mod.rs | 1 + crates/flipperzero/src/furi/time.rs | 9 +-- 4 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 crates/flipperzero/src/furi/kernel.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a0e3d5..08a2d068 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 00000000..65b9f17e --- /dev/null +++ b/crates/flipperzero/src/furi/kernel.rs @@ -0,0 +1,89 @@ +//! 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_irq_or_masked() } +} + +/// 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, + 1 => LockState::Locked, + x => panic!("invalid lock state value: {x}"), + } + } +} + +impl From for i32 { + fn from(value: LockState) -> Self { + value as i32 + } +} + +/// Lock kernel, pause process scheduling. +/// +/// **warning** 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. +/// +/// **warning** 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. +/// +/// **warning** 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 e14d0add..98fcbb79 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 c4c72f3d..843eefdc 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.