1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-08-02 11:58:32 +00:00

fixup! refactor(core/ui): reusable timers

This commit is contained in:
matejcik 2024-07-30 12:01:27 +02:00 committed by M1nd3r
parent 0d089d76a6
commit 780a22f68f

View File

@ -390,6 +390,11 @@ pub struct TimerToken(u32);
impl TimerToken { impl TimerToken {
/// Value of an invalid (or missing) token. /// Value of an invalid (or missing) token.
pub const INVALID: TimerToken = TimerToken(0); 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 { pub const fn from_raw(raw: u32) -> Self {
Self(raw) Self(raw)
@ -398,15 +403,38 @@ impl TimerToken {
pub const fn into_raw(self) -> u32 { pub const fn into_raw(self) -> u32 {
self.0 self.0
} }
pub fn next_token() -> Self {
static mut NEXT_TOKEN: TimerToken = Self(TimerToken::STARTING_TOKEN);
// SAFETY: we are in single-threaded environment
let token = unsafe { NEXT_TOKEN };
let next = {
if token.0 == u32::MAX {
TimerToken(Self::STARTING_TOKEN)
} else {
TimerToken(token.0 + 1)
}
};
// SAFETY: we are in single-threaded environment
unsafe { NEXT_TOKEN = next };
token
}
} }
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] #[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
pub struct Timer(Option<TimerToken>); pub struct Timer {
token: TimerToken,
running: bool,
}
impl Timer { impl Timer {
/// Create a new timer. /// Create a new timer.
pub const fn new() -> Self { pub const fn new() -> Self {
Self(None) Self {
token: TimerToken::INVALID,
running: false,
}
} }
/// Start this timer for a given duration. /// Start this timer for a given duration.
@ -414,8 +442,10 @@ impl Timer {
/// Requests the internal timer token to be scheduled to `duration` from /// Requests the internal timer token to be scheduled to `duration` from
/// now. If the timer was already running, its token is rescheduled. /// now. If the timer was already running, its token is rescheduled.
pub fn start(&mut self, ctx: &mut EventCtx, duration: Duration) { pub fn start(&mut self, ctx: &mut EventCtx, duration: Duration) {
let token = self.0.get_or_insert_with(|| ctx.next_timer_token()); if self.token == TimerToken::INVALID {
ctx.register_timer(*token, duration); self.token = TimerToken::next_token();
}
ctx.register_timer(self.token, duration);
} }
/// Stop the timer. /// Stop the timer.
@ -424,7 +454,7 @@ impl Timer {
/// means that _some_ scheduled task might keep running, but this timer /// means that _some_ scheduled task might keep running, but this timer
/// will not trigger when that task expires. /// will not trigger when that task expires.
pub fn stop(&mut self) { pub fn stop(&mut self) {
self.0 = None; self.running = false;
} }
/// Check if the timer has expired. /// Check if the timer has expired.
@ -432,13 +462,12 @@ impl Timer {
/// Returns `true` if the given event is a timer event and the token matches /// Returns `true` if the given event is a timer event and the token matches
/// the internal token of this timer. /// the internal token of this timer.
pub fn is_expired(&self, event: Event) -> bool { pub fn is_expired(&self, event: Event) -> bool {
matches!(event, Event::Timer(token) if self.0 == Some(token)) matches!(event, Event::Timer(token) if self.running && self.token == token)
} }
} }
pub struct EventCtx { pub struct EventCtx {
timers: Vec<(TimerToken, Duration), { Self::MAX_TIMERS }>, timers: Vec<(TimerToken, Duration), { Self::MAX_TIMERS }>,
next_token: u32,
place_requested: bool, place_requested: bool,
paint_requested: bool, paint_requested: bool,
anim_frame_scheduled: bool, anim_frame_scheduled: bool,
@ -457,17 +486,12 @@ impl EventCtx {
/// How long into the future we should schedule the animation frame timer. /// How long into the future we should schedule the animation frame timer.
const ANIM_FRAME_DURATION: Duration = Duration::from_millis(1); const ANIM_FRAME_DURATION: Duration = Duration::from_millis(1);
// 0 == `TimerToken::INVALID`,
// 1 == `Self::ANIM_FRAME_TIMER`.
const STARTING_TIMER_TOKEN: u32 = 2;
/// Maximum amount of timers requested in one event tick. /// Maximum amount of timers requested in one event tick.
const MAX_TIMERS: usize = 4; const MAX_TIMERS: usize = 4;
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
timers: Vec::new(), timers: Vec::new(),
next_token: Self::STARTING_TIMER_TOKEN,
place_requested: false, place_requested: false,
paint_requested: false, paint_requested: false,
anim_frame_scheduled: false, anim_frame_scheduled: false,
@ -572,10 +596,7 @@ impl EventCtx {
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
assert!(self.button_request.is_none()); assert!(self.button_request.is_none());
// replace self with a new instance, keeping only the fields we care about // replace self with a new instance, keeping only the fields we care about
*self = Self { *self = Self::new();
next_token: self.next_token,
..Self::new()
}
} }
fn register_timer(&mut self, token: TimerToken, duration: Duration) { fn register_timer(&mut self, token: TimerToken, duration: Duration) {
@ -587,18 +608,6 @@ impl EventCtx {
} }
} }
fn next_timer_token(&mut self) -> TimerToken {
let token = TimerToken(self.next_token);
// We start again from the beginning if the token counter overflows. This would
// probably happen in case of a bug and a long-running session. Let's risk the
// collisions in such case.
self.next_token = self
.next_token
.checked_add(1)
.unwrap_or(Self::STARTING_TIMER_TOKEN);
token
}
pub fn set_transition_out(&mut self, attach_type: AttachType) { pub fn set_transition_out(&mut self, attach_type: AttachType) {
self.transition_out = Some(attach_type); self.transition_out = Some(attach_type);
} }