tasks: use new animations api
This commit is contained in:
@@ -104,6 +104,9 @@ impl Animation<Fract8> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const MIN_ANIMATION_RATE: Duration = Duration::from_millis(5);
|
||||
|
||||
impl Animation<Fract8> {
|
||||
pub async fn apply<const ACTOR_COUNT: usize>(&self, actors: [&mut dyn AnimationActor<Fract8>; ACTOR_COUNT]) {
|
||||
|
||||
@@ -126,9 +129,11 @@ impl Animation<Fract8> {
|
||||
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<Fract8> {
|
||||
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<Fract8> {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ impl Shader<OledUniforms, Matrix2DSpace, BinaryColor> for OverlayShader {
|
||||
}
|
||||
|
||||
impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = BinaryColor, Uniforms = OledUniforms>> OledUI<S> {
|
||||
pub fn new<SS: Surfaces<Matrix2DSpace, Surface = S>>(surfaces: &mut SS, controls: DisplayControls, uniforms: LockedUniforms) -> Self where SS::Error: core::fmt::Debug {
|
||||
pub fn new<SS: Surfaces<Surface = S>>(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<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = Bina
|
||||
const FADE_IN: Animation<Fract8> = Animation::new().from(Fract8::MIN).to(Fract8::MAX).duration(Duration::from_millis(300));
|
||||
const FADE_OUT: Animation<Fract8> = 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) {
|
||||
|
||||
@@ -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<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
pub async fn sleep(&mut self) {
|
||||
info!("Running sleep sequence");
|
||||
let mut disp_anim = AnimDisplay(&mut self.display);
|
||||
TURN_OFF.apply(&mut disp_anim).await;
|
||||
TURN_OFF.apply([&mut disp_anim]).await;
|
||||
|
||||
warn!("Resetting safety lights");
|
||||
self.brakelight.set_visible(false);
|
||||
@@ -76,20 +76,17 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
trace!("Fading in brightness with overlay={:?}", self.overlay);
|
||||
self.overlay.set_opacity(Fract8::MAX);
|
||||
self.overlay.set_visible(true);
|
||||
fade_in.apply(&mut AnimDisplay(&mut self.display)).await;
|
||||
fade_in.apply([&mut AnimDisplay(&mut self.display)]).await;
|
||||
|
||||
warn!("Turning on safety lights");
|
||||
self.headlight.set_opacity(Fract8::MIN);
|
||||
self.headlight.set_visible(true);
|
||||
self.brakelight.set_opacity(Fract8::MIN);
|
||||
self.brakelight.set_visible(true);
|
||||
embassy_futures::join::join(
|
||||
fade_in.apply(&mut self.headlight),
|
||||
fade_in.apply(&mut self.brakelight)
|
||||
).await;
|
||||
fade_in.apply([&mut self.headlight, &mut self.brakelight]).await;
|
||||
|
||||
info!("Fade out overlay");
|
||||
TURN_OFF.apply(&mut self.overlay).await;
|
||||
TURN_OFF.apply([&mut self.overlay]).await;
|
||||
self.overlay.set_visible(false);
|
||||
info!("Wakeup complete!");
|
||||
}
|
||||
@@ -99,17 +96,17 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
Personality::Active => {
|
||||
// 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<Fract8> = Animation::new().duration(Duration::from_secs
|
||||
const TURN_OFF: Animation<Fract8> = 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<<UiSurfacePool as Surfaces<SegmentSpace>>::Surface>) {
|
||||
pub async fn safety_ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: SafetyUi<<UiSurfacePool as Surfaces>::Surface>) {
|
||||
// Wait for the renderer to start running
|
||||
//ui.display.render_is_running.wait().await;
|
||||
trace!("spooling until render starts ui={ui:?}");
|
||||
|
||||
@@ -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<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
|
||||
self.notification.set_shader(Background::from_color(color));
|
||||
|
||||
fade_in.apply(&mut self.notification).await;
|
||||
fade_in.apply([&mut self.notification]).await;
|
||||
|
||||
// Pulse quickly 5 times
|
||||
for _ in 0..5 {
|
||||
pulse_out.apply(&mut self.notification).await;
|
||||
pulse_in.apply(&mut self.notification).await;
|
||||
pulse_out.apply([&mut self.notification]).await;
|
||||
pulse_in.apply([&mut self.notification]).await;
|
||||
}
|
||||
|
||||
fade_out.apply(&mut self.notification).await;
|
||||
fade_out.apply([&mut self.notification]).await;
|
||||
self.notification.set_visible(false);
|
||||
}
|
||||
|
||||
@@ -100,10 +99,10 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
let bg = Animation::default().duration(Duration::from_millis(300)).to(Fract8::from_raw(32));
|
||||
let motion = Animation::default().duration(Duration::from_secs(1)).to(Fract8::MIN);
|
||||
embassy_futures::join::join4(
|
||||
tail.apply(&mut self.tail),
|
||||
panels.apply(&mut self.panels),
|
||||
bg.apply(&mut self.background),
|
||||
motion.apply(&mut self.motion)
|
||||
tail.apply([&mut self.tail]),
|
||||
panels.apply([&mut self.panels]),
|
||||
bg.apply([&mut self.background]),
|
||||
motion.apply([&mut self.motion])
|
||||
).await;
|
||||
self.background.set_shader(Background::default());
|
||||
},
|
||||
@@ -114,20 +113,18 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
let bg_fade = Animation::default().duration(Duration::from_millis(300)).to(Fract8::from_raw(128));
|
||||
|
||||
// FIXME: The scenes shouldn't be touching the brake/headlights at all here. In fact, they should be dealt with in a whole separate task from the main UI, maybe running on the motion prediction executor
|
||||
embassy_futures::join::join4(
|
||||
fg_fade.apply(&mut self.tail),
|
||||
fg_fade.apply(&mut self.panels),
|
||||
bg_fade.apply(&mut self.background),
|
||||
fg_fade.apply(&mut self.motion)
|
||||
embassy_futures::join::join(
|
||||
fg_fade.apply([&mut self.tail, &mut self.panels, &mut self.motion]),
|
||||
bg_fade.apply([&mut self.background])
|
||||
).await;
|
||||
},
|
||||
Scene::Accelerating => {
|
||||
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<Uniforms, SegmentSpace, Rgba<u8>>;
|
||||
pub type UiSurfacePool = BufferedSurfacePool<Uniforms, SegmentSpace, Rgba<u8>>;
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: Ui<<UiSurfacePool as Surfaces<SegmentSpace>>::Surface>) {
|
||||
pub async fn ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: Ui<<UiSurfacePool as Surfaces>::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;
|
||||
|
||||
Reference in New Issue
Block a user