events: rewrite the eventing system to reduce mutex usage to just the measurement bus

This commit is contained in:
2025-12-24 09:11:16 +01:00
parent 36f232f43c
commit 046406291a
11 changed files with 185 additions and 284 deletions

View File

@@ -1,4 +1,4 @@
use embassy_sync::pubsub::{DynPublisher, DynSubscriber};
use embassy_sync::pubsub::DynSubscriber;
use embassy_time::{Duration, Timer};
use figments::prelude::*;
use rgb::{Rgb, Rgba};
@@ -6,7 +6,7 @@ use core::fmt::Debug;
use futures::join;
use log::*;
use crate::{animation::{AnimatedSurface, Animation}, events::{Notification, Scene, SensorSource, SensorState, Telemetry}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}};
use crate::{animation::{AnimatedSurface, Animation}, ego::engine::MotionState, events::{Personality, Prediction, Scene, SensorSource, SensorState}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}};
pub struct Ui<S: Surface> {
// Background layer provides an always-running background for everything to draw on
@@ -132,33 +132,32 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
}
}
pub async fn on_event(&mut self, event: Notification) {
pub async fn on_event(&mut self, event: Prediction) {
match event {
Notification::SceneChange(_) => (), // We already log this inside apply_scene()
evt => info!("UI event: {evt:?}")
}
match event {
// TODO: We probably also want some events to indicate when the ESP has no calibration data or otherwise needs re-calibrated and is waiting for the bike to stand still
Notification::SensorStatus(SensorSource::IMU, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
Notification::SensorStatus(SensorSource::Location, SensorState::Degraded) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
Notification::SensorStatus(SensorSource::GPS, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
// Scene change
Notification::SceneChange(scene) => self.apply_scene(scene).await,
Notification::WakeUp => self.show().await,
Prediction::SetPersonality(personality) => match personality {
Personality::Active => self.apply_scene(Scene::Ready).await,
Personality::Parked => self.apply_scene(Scene::Idle).await,
Personality::Waking => self.show().await,
_ => ()
},
Prediction::Motion { prev: _, next: MotionState::Accelerating } => self.apply_scene(Scene::Accelerating).await,
Prediction::Motion { prev: _, next: MotionState::Decelerating } => self.apply_scene(Scene::Decelerating).await,
Prediction::Motion { prev: _, next: MotionState::Steady } => self.apply_scene(Scene::Ready).await,
Prediction::Motion { prev: _, next: MotionState::Stationary } => self.apply_scene(Scene::Ready).await,
Prediction::SensorStatus(SensorSource::IMU, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
Prediction::SensorStatus(SensorSource::Location, SensorState::Degraded) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
Prediction::SensorStatus(SensorSource::GPS, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
_ => ()
// Other event ideas:
// - Bike has crashed, or is laid down
// - Unstable physics right before crashing?
// - Turning left/right
// - BPM sync with phone app
// - GPS data is being synchronized with nextcloud/whatever
// - A periodic flash when re-initializing MPU and GPS, to indicate there might be a problem?
// - Bluetooth/BLE connect/disconnect events
// - Bike is waking up from stationary?
}
// Other event ideas:
// - Bike has crashed, or is laid down
// - Unstable physics right before crashing?
// - Turning left/right
// - BPM sync with phone app
// - GPS data is being synchronized with nextcloud/whatever
// - A periodic flash when re-initializing MPU and GPS, to indicate there might be a problem?
// - Bluetooth/BLE connect/disconnect events
// - Bike is waking up from stationary?
}
}
@@ -200,7 +199,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, Notification>, telemetery: DynPublisher<'static, Telemetry>, mut ui: Ui<<UiSurfacePool as Surfaces<SegmentSpace>>::Surface>) {
pub async fn ui_main(mut events: DynSubscriber<'static, Prediction>, mut ui: Ui<<UiSurfacePool as Surfaces<SegmentSpace>>::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;
@@ -212,6 +211,5 @@ pub async fn ui_main(mut events: DynSubscriber<'static, Notification>, telemeter
loop {
let evt = events.next_message_pure().await;
ui.on_event(evt).await;
telemetery.publish(Telemetry::Notification(evt)).await;
}
}