Skip to content

Commit

Permalink
Standardize use of furi::time::Duration
Browse files Browse the repository at this point in the history
Most places use `furi::time::Duration` for things like timeouts,
though there are a few place that used `core::time::Duration`
(typically before `furi::time::Duration`).

I left `furi::thread::sleep` unchanged but introduced a new
`sleep_ticks` to specifically support `furi::time::Duration`.
  • Loading branch information
dcoles committed Oct 21, 2024
1 parent cb902c2 commit 2c8a988
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 18 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- `flipperzero::dialogs::DialogFileBrowserOptions`
- `as_ticks()` method to `flipperzero::furi::time::Duration`
- `flipperzero::furi::thread::sleep_ticks` function to sleep for exact duration
- `TryFrom<core::time::Duration>` for `flipperzero::furi::time::Duration`

### Changed

Expand All @@ -18,6 +21,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Removed

- `flipperzero::furi::duration_to_ticks` in favour of `TryFrom` traits

## [0.12.0]

### Added
Expand Down
12 changes: 5 additions & 7 deletions crates/flipperzero/src/furi/message_queue.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use core::ffi::c_void;
use core::ptr::NonNull;
use core::time::Duration;

use flipperzero_sys as sys;
use flipperzero_sys::furi::{duration_to_ticks, Status};
use flipperzero_sys::furi::Status;

use crate::furi;
use crate::furi::time::Duration;

/// MessageQueue provides a safe wrapper around the furi message queue primitive.
pub struct MessageQueue<M: Sized> {
Expand All @@ -30,13 +30,12 @@ impl<M: Sized> MessageQueue<M> {
// Attempts to add the message to the end of the queue, waiting up to timeout ticks.
pub fn put(&self, msg: M, timeout: Duration) -> furi::Result<()> {
let mut msg = core::mem::ManuallyDrop::new(msg);
let timeout_ticks = duration_to_ticks(timeout);

let status: Status = unsafe {
sys::furi_message_queue_put(
self.hnd.as_ptr(),
&mut msg as *mut _ as *const c_void,
timeout_ticks,
timeout.as_ticks(),
)
.into()
};
Expand All @@ -46,13 +45,12 @@ impl<M: Sized> MessageQueue<M> {

// Attempts to read a message from the front of the queue within timeout ticks.
pub fn get(&self, timeout: Duration) -> furi::Result<M> {
let timeout_ticks = duration_to_ticks(timeout);
let mut out = core::mem::MaybeUninit::<M>::uninit();
let status: Status = unsafe {
sys::furi_message_queue_get(
self.hnd.as_ptr(),
out.as_mut_ptr() as *mut c_void,
timeout_ticks,
timeout.as_ticks(),
)
.into()
};
Expand Down Expand Up @@ -102,7 +100,7 @@ impl<M: Sized> Drop for MessageQueue<M> {

#[flipperzero_test::tests]
mod tests {
use core::time::Duration;
use super::*;

use flipperzero_sys::furi::Status;

Expand Down
11 changes: 11 additions & 0 deletions crates/flipperzero/src/furi/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use alloc::{

use flipperzero_sys as sys;

use crate::furi::time::Duration;

#[cfg(feature = "alloc")]
const MIN_STACK_SIZE: usize = 1024;

Expand Down Expand Up @@ -203,6 +205,15 @@ pub fn sleep(duration: core::time::Duration) {
}
}

/// Puts the current thread to sleep for at least the specified amount of time.
///
/// This differs from [`sleep`] in that a Furi [`Duration`] can represent an exact number of ticks.
pub fn sleep_ticks(duration: Duration) {
unsafe {
sys::furi_delay_tick(duration.as_ticks());
}
}

/// A unique identifier for a running thread.
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
Expand Down
48 changes: 47 additions & 1 deletion crates/flipperzero/src/furi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ impl Duration {
self.0 == 0
}

/// Duration as Furi Kernel ticks.
#[inline]
pub const fn as_ticks(&self) -> u32 {
self.0
}

/// Returns the total number of whole seconds contained by this `Duration`.
#[inline]
#[must_use]
Expand Down Expand Up @@ -464,9 +470,36 @@ impl<'a> Sum<&'a Duration> for Duration {
}
}

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, uDebug)]
pub struct TryFromDurationError;

impl core::error::Error for TryFromDurationError {}

impl core::fmt::Display for TryFromDurationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("duration exceeds supported representation")
}
}

impl TryFrom<core::time::Duration> for Duration {
type Error = TryFromDurationError;

fn try_from(value: core::time::Duration) -> Result<Self, Self::Error> {
let nanos: u64 = value
.as_nanos()
.try_into()
.map_err(|_| TryFromDurationError)?;
let ticks: u32 = ns_to_ticks(nanos)
.try_into()
.map_err(|_| TryFromDurationError)?;

Ok(Duration(ticks))
}
}

#[flipperzero_test::tests]
mod tests {
use super::{ticks_to_ns, Duration, Instant, MAX_INTERVAL_DURATION_TICKS};
use super::*;
use crate::println;

#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -622,4 +655,17 @@ mod tests {
check(instant.checked_add(Duration(100)), Instant::checked_sub);
check(instant.checked_add(Duration::MAX), Instant::checked_sub);
}

#[test]
fn duration_try_from() {
assert_eq!(
Duration::try_from(core::time::Duration::ZERO),
Ok(Duration(0))
);

assert_eq!(
Duration::try_from(core::time::Duration::MAX),
Err(TryFromDurationError)
)
}
}
10 changes: 0 additions & 10 deletions crates/sys/src/furi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use core::ffi::c_char;
use core::fmt::Display;
use core::time::Duration;

/// Operation status.
/// The Furi API switches between using `enum FuriStatus`, `int32_t` and `uint32_t`.
Expand Down Expand Up @@ -127,12 +126,3 @@ impl<T> Drop for UnsafeRecord<T> {
}
}
}

/// Convert [`Duration`] to ticks.
#[inline]
pub fn duration_to_ticks(duration: Duration) -> u32 {
// This maxes out at about 50 days
let duration_ms: u32 = duration.as_millis().try_into().unwrap_or(u32::MAX);

unsafe { crate::furi_ms_to_ticks(duration_ms) }
}

0 comments on commit 2c8a988

Please sign in to comment.