diff --git a/src/animation.rs b/src/animation.rs index c84c025..da73d72 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -104,6 +104,9 @@ impl Animation { } } + +const MIN_ANIMATION_RATE: Duration = Duration::from_millis(5); + impl Animation { pub async fn apply(&self, actors: [&mut dyn AnimationActor; ACTOR_COUNT]) { @@ -126,9 +129,11 @@ impl Animation { let steps = to.abs_diff(from); let step_time = if steps == Fract8::MIN { + // Zero ticks is an 'invalid' animator that shouldn't get processed because start == end already Duration::from_ticks(0) } else { - (self.duration / steps.to_raw().into()).max(Duration::from_millis(1)) + // FIXME: if the resulting duration is less than the animation rate, we also need to re-scale the number added to animator.cur_step further down below. Otherwise a 0-255 animation with a 100ms duration actually ends up running for 255ms + (self.duration / steps.to_raw().into()).max(MIN_ANIMATION_RATE) }; Slot { from, @@ -163,10 +168,6 @@ impl Animation { finished = true; } - /*if animator.cur_step == animator.from || animator.cur_step == animator.to { - finished = true; - }*/ - animator.target.set_value(animator.cur_step); } @@ -180,7 +181,7 @@ impl Animation { } let keyframe_delay = next_keyframe_time - now; - trace!("delay {keyframe_delay:?}"); + trace!("delay {:?}", keyframe_delay.as_millis()); Timer::after(keyframe_delay).await; now += keyframe_delay; } diff --git a/src/tasks/oled.rs b/src/tasks/oled.rs index 4799525..45dbe49 100644 --- a/src/tasks/oled.rs +++ b/src/tasks/oled.rs @@ -32,7 +32,7 @@ impl Shader for OverlayShader { } impl> OledUI { - pub fn new>(surfaces: &mut SS, controls: DisplayControls, uniforms: LockedUniforms) -> Self where SS::Error: core::fmt::Debug { + pub fn new>(surfaces: &mut SS, controls: DisplayControls, uniforms: LockedUniforms) -> Self where SS::Error: core::fmt::Debug { Self { overlay: SurfaceBuilder::build(surfaces) .rect(Rectangle::everything()) @@ -48,12 +48,12 @@ impl = Animation::new().from(Fract8::MIN).to(Fract8::MAX).duration(Duration::from_millis(300)); const FADE_OUT: Animation = Animation::new().from(Fract8::MAX).to(Fract8::MIN).duration(Duration::from_millis(300)); info!("Fading in to screen {next_screen:?}"); - FADE_IN.apply(&mut self.overlay).await; + FADE_IN.apply([&mut self.overlay]).await; { let mut locked = self.uniforms.lock().await; locked.current_screen = next_screen; } - FADE_OUT.apply(&mut self.overlay).await; + FADE_OUT.apply([&mut self.overlay]).await; } pub async fn on_event(&mut self, event: Prediction) { diff --git a/src/tasks/safetyui.rs b/src/tasks/safetyui.rs index a0623e3..dfaa47c 100644 --- a/src/tasks/safetyui.rs +++ b/src/tasks/safetyui.rs @@ -1,6 +1,6 @@ use embassy_sync::pubsub::DynSubscriber; use embassy_time::Duration; -use figments::prelude::*; +use figments::{liber8tion::interpolate::Fract8, prelude::*}; use figments_render::output::Brightness; use rgb::Rgba; use core::fmt::Debug; @@ -48,7 +48,7 @@ impl { // FIXME: These should be a Off/Low/High enum, so the stopping brake looks different from the dayrunning brake. warn!("Active personality: Turning on safety lights"); - embassy_futures::join::join( - TURN_ON.apply(&mut self.brakelight), - TURN_ON.apply(&mut self.headlight) - ).await; + TURN_ON.apply([ + &mut self.brakelight, + &mut self.headlight + ]).await; }, Personality::Parked => { warn!("Idle personality: Turning off safety lights"); - embassy_futures::join::join( - TURN_OFF.apply(&mut self.brakelight), - TURN_OFF.apply(&mut self.headlight) - ).await; + TURN_OFF.apply([ + &mut self.brakelight, + &mut self.headlight + ]).await; }, Personality::Sleeping => { warn!("Sleeping personality: Safety UI is going to sleep"); @@ -127,7 +124,7 @@ const TURN_ON: Animation = Animation::new().duration(Duration::from_secs const TURN_OFF: Animation = Animation::new().duration(Duration::from_secs(1)).from(Fract8::MAX).to(Fract8::MIN); #[embassy_executor::task] -pub async fn safety_ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: SafetyUi<>::Surface>) { +pub async fn safety_ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: SafetyUi<::Surface>) { // Wait for the renderer to start running //ui.display.render_is_running.wait().await; trace!("spooling until render starts ui={ui:?}"); diff --git a/src/tasks/ui.rs b/src/tasks/ui.rs index 300e0ec..7df9c1c 100644 --- a/src/tasks/ui.rs +++ b/src/tasks/ui.rs @@ -1,9 +1,8 @@ use embassy_sync::pubsub::DynSubscriber; use embassy_time::{Duration, Timer}; -use figments::prelude::*; +use figments::{liber8tion::interpolate::Fract8, prelude::*}; use rgb::{Rgb, Rgba}; use core::fmt::Debug; -use futures::join; use log::*; use crate::{animation::{AnimatedSurface, Animation}, ego::engine::MotionState, events::{Personality, Prediction, Scene, SensorSource, SensorState}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}}; @@ -64,15 +63,15 @@ impl { self.motion.set_shader(Movement::default()); - Animation::default().duration(Duration::from_secs(1)).to(255).apply(&mut self.motion).await; + Animation::default().duration(Duration::from_secs(1)).to(Fract8::MAX).apply([&mut self.motion]).await; }, Scene::Decelerating => { self.motion.set_shader(Movement::default().reversed()); - Animation::default().duration(Duration::from_secs(1)).to(255).apply(&mut self.motion).await; + Animation::default().duration(Duration::from_secs(1)).to(Fract8::MAX).apply([&mut self.motion]).await; } } } @@ -199,7 +196,7 @@ pub type UiSurfacePool = NullBufferPool>; pub type UiSurfacePool = BufferedSurfacePool>; #[embassy_executor::task] -pub async fn ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: Ui<>::Surface>) { +pub async fn ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: Ui<::Surface>) { // FIXME: This should instead wait on some kind of flag set by the safety UI, or else we risk painting before we even have a display up and running Timer::after_secs(3).await; ui.show().await;