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> {
|
impl Animation<Fract8> {
|
||||||
pub async fn apply<const ACTOR_COUNT: usize>(&self, actors: [&mut dyn AnimationActor<Fract8>; ACTOR_COUNT]) {
|
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 steps = to.abs_diff(from);
|
||||||
|
|
||||||
let step_time = if steps == Fract8::MIN {
|
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)
|
Duration::from_ticks(0)
|
||||||
} else {
|
} 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 {
|
Slot {
|
||||||
from,
|
from,
|
||||||
@@ -163,10 +168,6 @@ impl Animation<Fract8> {
|
|||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if animator.cur_step == animator.from || animator.cur_step == animator.to {
|
|
||||||
finished = true;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
animator.target.set_value(animator.cur_step);
|
animator.target.set_value(animator.cur_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ impl Animation<Fract8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let keyframe_delay = next_keyframe_time - now;
|
let keyframe_delay = next_keyframe_time - now;
|
||||||
trace!("delay {keyframe_delay:?}");
|
trace!("delay {:?}", keyframe_delay.as_millis());
|
||||||
Timer::after(keyframe_delay).await;
|
Timer::after(keyframe_delay).await;
|
||||||
now += keyframe_delay;
|
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> {
|
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 {
|
Self {
|
||||||
overlay: SurfaceBuilder::build(surfaces)
|
overlay: SurfaceBuilder::build(surfaces)
|
||||||
.rect(Rectangle::everything())
|
.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_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));
|
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:?}");
|
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;
|
let mut locked = self.uniforms.lock().await;
|
||||||
locked.current_screen = next_screen;
|
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) {
|
pub async fn on_event(&mut self, event: Prediction) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use embassy_sync::pubsub::DynSubscriber;
|
use embassy_sync::pubsub::DynSubscriber;
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
use figments::prelude::*;
|
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
||||||
use figments_render::output::Brightness;
|
use figments_render::output::Brightness;
|
||||||
use rgb::Rgba;
|
use rgb::Rgba;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
@@ -48,7 +48,7 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
|||||||
pub async fn sleep(&mut self) {
|
pub async fn sleep(&mut self) {
|
||||||
info!("Running sleep sequence");
|
info!("Running sleep sequence");
|
||||||
let mut disp_anim = AnimDisplay(&mut self.display);
|
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");
|
warn!("Resetting safety lights");
|
||||||
self.brakelight.set_visible(false);
|
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);
|
trace!("Fading in brightness with overlay={:?}", self.overlay);
|
||||||
self.overlay.set_opacity(Fract8::MAX);
|
self.overlay.set_opacity(Fract8::MAX);
|
||||||
self.overlay.set_visible(true);
|
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");
|
warn!("Turning on safety lights");
|
||||||
self.headlight.set_opacity(Fract8::MIN);
|
self.headlight.set_opacity(Fract8::MIN);
|
||||||
self.headlight.set_visible(true);
|
self.headlight.set_visible(true);
|
||||||
self.brakelight.set_opacity(Fract8::MIN);
|
self.brakelight.set_opacity(Fract8::MIN);
|
||||||
self.brakelight.set_visible(true);
|
self.brakelight.set_visible(true);
|
||||||
embassy_futures::join::join(
|
fade_in.apply([&mut self.headlight, &mut self.brakelight]).await;
|
||||||
fade_in.apply(&mut self.headlight),
|
|
||||||
fade_in.apply(&mut self.brakelight)
|
|
||||||
).await;
|
|
||||||
|
|
||||||
info!("Fade out overlay");
|
info!("Fade out overlay");
|
||||||
TURN_OFF.apply(&mut self.overlay).await;
|
TURN_OFF.apply([&mut self.overlay]).await;
|
||||||
self.overlay.set_visible(false);
|
self.overlay.set_visible(false);
|
||||||
info!("Wakeup complete!");
|
info!("Wakeup complete!");
|
||||||
}
|
}
|
||||||
@@ -99,17 +96,17 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
|||||||
Personality::Active => {
|
Personality::Active => {
|
||||||
// FIXME: These should be a Off/Low/High enum, so the stopping brake looks different from the dayrunning brake.
|
// 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");
|
warn!("Active personality: Turning on safety lights");
|
||||||
embassy_futures::join::join(
|
TURN_ON.apply([
|
||||||
TURN_ON.apply(&mut self.brakelight),
|
&mut self.brakelight,
|
||||||
TURN_ON.apply(&mut self.headlight)
|
&mut self.headlight
|
||||||
).await;
|
]).await;
|
||||||
},
|
},
|
||||||
Personality::Parked => {
|
Personality::Parked => {
|
||||||
warn!("Idle personality: Turning off safety lights");
|
warn!("Idle personality: Turning off safety lights");
|
||||||
embassy_futures::join::join(
|
TURN_OFF.apply([
|
||||||
TURN_OFF.apply(&mut self.brakelight),
|
&mut self.brakelight,
|
||||||
TURN_OFF.apply(&mut self.headlight)
|
&mut self.headlight
|
||||||
).await;
|
]).await;
|
||||||
},
|
},
|
||||||
Personality::Sleeping => {
|
Personality::Sleeping => {
|
||||||
warn!("Sleeping personality: Safety UI is going to sleep");
|
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);
|
const TURN_OFF: Animation<Fract8> = Animation::new().duration(Duration::from_secs(1)).from(Fract8::MAX).to(Fract8::MIN);
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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
|
// Wait for the renderer to start running
|
||||||
//ui.display.render_is_running.wait().await;
|
//ui.display.render_is_running.wait().await;
|
||||||
trace!("spooling until render starts ui={ui:?}");
|
trace!("spooling until render starts ui={ui:?}");
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use embassy_sync::pubsub::DynSubscriber;
|
use embassy_sync::pubsub::DynSubscriber;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use figments::prelude::*;
|
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
||||||
use rgb::{Rgb, Rgba};
|
use rgb::{Rgb, Rgba};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use futures::join;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use crate::{animation::{AnimatedSurface, Animation}, ego::engine::MotionState, events::{Personality, Prediction, Scene, SensorSource, SensorState}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}};
|
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));
|
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
|
// Pulse quickly 5 times
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
pulse_out.apply(&mut self.notification).await;
|
pulse_out.apply([&mut self.notification]).await;
|
||||||
pulse_in.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);
|
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 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);
|
let motion = Animation::default().duration(Duration::from_secs(1)).to(Fract8::MIN);
|
||||||
embassy_futures::join::join4(
|
embassy_futures::join::join4(
|
||||||
tail.apply(&mut self.tail),
|
tail.apply([&mut self.tail]),
|
||||||
panels.apply(&mut self.panels),
|
panels.apply([&mut self.panels]),
|
||||||
bg.apply(&mut self.background),
|
bg.apply([&mut self.background]),
|
||||||
motion.apply(&mut self.motion)
|
motion.apply([&mut self.motion])
|
||||||
).await;
|
).await;
|
||||||
self.background.set_shader(Background::default());
|
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));
|
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
|
// 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(
|
embassy_futures::join::join(
|
||||||
fg_fade.apply(&mut self.tail),
|
fg_fade.apply([&mut self.tail, &mut self.panels, &mut self.motion]),
|
||||||
fg_fade.apply(&mut self.panels),
|
bg_fade.apply([&mut self.background])
|
||||||
bg_fade.apply(&mut self.background),
|
|
||||||
fg_fade.apply(&mut self.motion)
|
|
||||||
).await;
|
).await;
|
||||||
},
|
},
|
||||||
Scene::Accelerating => {
|
Scene::Accelerating => {
|
||||||
self.motion.set_shader(Movement::default());
|
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 => {
|
Scene::Decelerating => {
|
||||||
self.motion.set_shader(Movement::default().reversed());
|
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>>;
|
pub type UiSurfacePool = BufferedSurfacePool<Uniforms, SegmentSpace, Rgba<u8>>;
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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
|
// 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;
|
Timer::after_secs(3).await;
|
||||||
ui.show().await;
|
ui.show().await;
|
||||||
|
|||||||
Reference in New Issue
Block a user