Skip to content

Commit

Permalink
Add flipperzero::furi::kernel module
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dcoles committed Oct 22, 2024
1 parent cb902c2 commit 0e9fde7
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
90 changes: 90 additions & 0 deletions crates/flipperzero/src/furi/kernel.rs
Original file line number Diff line number Diff line change
@@ -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<i32> 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<LockState> for i32 {
fn from(value: LockState) -> Self {
value as i32
}
}

/// Lock kernel, pause process scheduling.
///
/// <div class="warning">This should never be called in an interrupt request context.</div>
///
/// Returns previous lock state.
pub fn lock() -> furi::Result<LockState> {
let status = sys::furi::Status::from(unsafe { sys::furi_kernel_lock() });

status.err_or_else(|status| status.0.into())
}

/// Unlock kernel, resume process scheduling.
///
/// <div class="warning">This should never be called in an interrupt request context.</div>
///
/// Returns previous lock state.
pub fn unlock() -> furi::Result<LockState> {
let status = sys::furi::Status::from(unsafe { sys::furi_kernel_unlock() });

status.err_or_else(|status| status.0.into())
}

/// Restore kernel lock state.
///
/// <div class="warning">This should never be called in an interrupt request context.</div>
///
/// Returns previous lock state.
pub fn restore_lock(state: LockState) -> furi::Result<LockState> {
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() }
}
1 change: 1 addition & 0 deletions crates/flipperzero/src/furi/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Furi API.

pub mod io;
pub mod kernel;
pub mod log;
pub mod message_queue;
pub mod rng;
Expand Down
9 changes: 5 additions & 4 deletions crates/flipperzero/src/furi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down

0 comments on commit 0e9fde7

Please sign in to comment.