mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-28 11:48:45 +00:00
perf(core): encode Timer
using a single u32
[no changelog]
This commit is contained in:
parent
9037c398eb
commit
f20c2d551d
@ -1,6 +1,7 @@
|
||||
use heapless::Vec;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
strutil::{ShortString, TString},
|
||||
time::Duration,
|
||||
ui::{
|
||||
@ -359,53 +360,68 @@ pub enum EventPropagation {
|
||||
pub struct TimerToken(u32);
|
||||
|
||||
impl TimerToken {
|
||||
/// Value of an invalid (or missing) token.
|
||||
pub const INVALID: TimerToken = TimerToken(0);
|
||||
/// Reserved value of the animation frame timer.
|
||||
pub const ANIM_FRAME: TimerToken = TimerToken(1);
|
||||
|
||||
/// Starting token value
|
||||
const STARTING_TOKEN: u32 = 2;
|
||||
|
||||
pub const fn from_raw(raw: u32) -> Self {
|
||||
Self(raw)
|
||||
pub const fn from_raw(raw: u32) -> Result<Self, Error> {
|
||||
if raw == Timer::INVALID_TOKEN_VALUE || raw > Timer::TOKEN_BITMASK {
|
||||
return Err(Error::ValueError(c"Invalid token"));
|
||||
}
|
||||
Ok(Self(raw))
|
||||
}
|
||||
|
||||
pub const fn into_raw(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
|
||||
pub struct Timer(u32);
|
||||
|
||||
pub fn next_token() -> Self {
|
||||
static mut NEXT_TOKEN: TimerToken = Self(TimerToken::STARTING_TOKEN);
|
||||
impl Timer {
|
||||
/// Value of an invalid (or missing) token.
|
||||
const INVALID_TOKEN_VALUE: u32 = 0;
|
||||
|
||||
/// Reserved value of the animation frame timer.
|
||||
const ANIM_FRAME: TimerToken = TimerToken(1);
|
||||
|
||||
/// Starting token value
|
||||
const STARTING_TOKEN: u32 = 2;
|
||||
|
||||
const IS_RUNNING_BITMASK: u32 = 1 << 31;
|
||||
const TOKEN_BITMASK: u32 = Timer::IS_RUNNING_BITMASK - 1;
|
||||
|
||||
fn next_token() -> u32 {
|
||||
static mut NEXT_TOKEN: u32 = Timer::STARTING_TOKEN;
|
||||
|
||||
// SAFETY: we are in single-threaded environment
|
||||
let token = unsafe { NEXT_TOKEN };
|
||||
debug_assert!(token >= Timer::STARTING_TOKEN);
|
||||
debug_assert!(token <= Timer::TOKEN_BITMASK);
|
||||
let next = {
|
||||
if token.0 == u32::MAX {
|
||||
TimerToken(Self::STARTING_TOKEN)
|
||||
if token == Timer::TOKEN_BITMASK {
|
||||
Self::STARTING_TOKEN
|
||||
} else {
|
||||
TimerToken(token.0 + 1)
|
||||
token + 1
|
||||
}
|
||||
};
|
||||
// SAFETY: we are in single-threaded environment
|
||||
unsafe { NEXT_TOKEN = next };
|
||||
token
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
|
||||
pub struct Timer {
|
||||
token: TimerToken,
|
||||
running: bool,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
/// Create a new timer.
|
||||
/// Create a new stopped timer.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
token: TimerToken::INVALID,
|
||||
running: false,
|
||||
}
|
||||
Self(Timer::INVALID_TOKEN_VALUE)
|
||||
}
|
||||
|
||||
const fn token(&self) -> TimerToken {
|
||||
TimerToken(self.0 & Timer::TOKEN_BITMASK)
|
||||
}
|
||||
|
||||
const fn is_invalid(&self) -> bool {
|
||||
self.token().0 == Timer::INVALID_TOKEN_VALUE
|
||||
}
|
||||
|
||||
const fn is_running(&self) -> bool {
|
||||
self.0 & Timer::IS_RUNNING_BITMASK != 0
|
||||
}
|
||||
|
||||
/// Start this timer for a given duration.
|
||||
@ -413,11 +429,11 @@ impl Timer {
|
||||
/// Requests the internal timer token to be scheduled to `duration` from
|
||||
/// now. If the timer was already running, its token is rescheduled.
|
||||
pub fn start(&mut self, ctx: &mut EventCtx, duration: Duration) {
|
||||
if self.token == TimerToken::INVALID {
|
||||
self.token = TimerToken::next_token();
|
||||
if self.is_invalid() {
|
||||
self.0 = Timer::next_token(); // new stopped timer
|
||||
}
|
||||
self.running = true;
|
||||
ctx.register_timer(self.token, duration);
|
||||
self.0 |= Timer::IS_RUNNING_BITMASK;
|
||||
ctx.register_timer(self.token(), duration);
|
||||
}
|
||||
|
||||
/// Stop the timer.
|
||||
@ -426,7 +442,7 @@ impl Timer {
|
||||
/// means that _some_ scheduled task might keep running, but this timer
|
||||
/// will not trigger when that task expires.
|
||||
pub fn stop(&mut self) {
|
||||
self.running = false;
|
||||
self.0 &= Timer::TOKEN_BITMASK;
|
||||
}
|
||||
|
||||
/// Check if the timer has expired.
|
||||
@ -434,8 +450,8 @@ impl Timer {
|
||||
/// Returns `true` if the given event is a timer event and the token matches
|
||||
/// the internal token of this timer.
|
||||
pub fn expire(&mut self, event: Event) -> bool {
|
||||
if self.running && event == Event::Timer(self.token) {
|
||||
self.running = false;
|
||||
if self.is_running() && event == Event::Timer(self.token()) {
|
||||
self.stop();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -458,7 +474,7 @@ pub struct EventCtx {
|
||||
|
||||
impl EventCtx {
|
||||
/// Timer token dedicated for animation frames.
|
||||
pub const ANIM_FRAME_TIMER: TimerToken = TimerToken(1);
|
||||
pub const ANIM_FRAME_TIMER: TimerToken = Timer::ANIM_FRAME;
|
||||
|
||||
/// How long into the future we should schedule the animation frame timer.
|
||||
const ANIM_FRAME_DURATION: Duration = Duration::from_millis(1);
|
||||
|
@ -444,7 +444,7 @@ impl TryFrom<Obj> for TimerToken {
|
||||
|
||||
fn try_from(value: Obj) -> Result<Self, Self::Error> {
|
||||
let raw: u32 = value.try_into()?;
|
||||
let this = Self::from_raw(raw);
|
||||
let this = Self::from_raw(raw)?;
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user