display: make DisplayControls cloneable in a multi-thread context

This commit is contained in:
2025-10-17 14:38:49 +02:00
parent d957615d4e
commit eb9f949e4e
5 changed files with 130 additions and 82 deletions

View File

@@ -2,9 +2,8 @@
use embassy_sync::{blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}, channel::Channel, pubsub::PubSubChannel};
use embassy_time::Duration;
use nalgebra::{Vector2, Vector3};
use alloc::sync::Arc;
use crate::ego::engine::MotionState;
use crate::{display::DisplayControls, ego::engine::MotionState};
#[derive(Clone, Copy, Default, Debug)]
pub enum Scene {
@@ -60,7 +59,13 @@ pub enum Notification {
SetBrakelight(bool),
// TODO: BPM detection via bluetooth
Beat
Beat,
}
#[derive(Clone, Copy, Debug)]
pub enum Telemetry {
Notification(Notification),
Prediction(Prediction),
}
#[derive(Clone, Copy, Debug)]
@@ -69,71 +74,13 @@ pub enum SensorSource {
GPS
}
// TODO: Make this clone() able, so multiple threads can point to the same underlying atomics for the hardware controls
// FIXME: We only ever hold this behind an Arc and therefore end up storing a Signal inside of an Arc<>... which defeats the whole purpose and can introduce a deadlock
pub struct DisplayControls {
on: AtomicBool,
brightness: AtomicU8,
// FIXME: This should get turned into a embassy_sync::Watch sender, so multiple tasks can wait on the renderer to be running.
pub render_is_running: Signal<CriticalSectionRawMutex, bool>,
render_pause: Signal<CriticalSectionRawMutex, bool>
}
impl DisplayControls {
pub fn is_on(&self) -> bool {
self.on.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn brightness(&self) -> u8 {
self.brightness.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn set_brightness(&self, brightness: u8) {
self.brightness.store(brightness, core::sync::atomic::Ordering::Relaxed);
}
// FIXME: its a bit weird we have a pub function for the renderer's privates to wait while hiding render_pause, but directly expose render_is_running for any task to wait on
pub async fn wait_for_on(&self) {
self.render_pause.wait().await;
}
pub fn set_on(&self, is_on: bool) {
self.on.store(is_on, core::sync::atomic::Ordering::Relaxed);
if is_on {
self.render_pause.signal(true);
} else {
self.render_pause.reset();
}
}
}
impl core::fmt::Debug for DisplayControls {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct("DisplayControls")
.field("on", &self.on)
.field("brightness", &self.brightness)
.field("render_is_running", &self.render_is_running.signaled())
.finish()
}
}
impl Default for DisplayControls {
fn default() -> Self {
Self {
on: AtomicBool::new(true),
brightness: AtomicU8::new(255),
render_is_running: Signal::new(),
render_pause: Signal::new()
}
}
}
#[derive(Debug)]
pub struct BusGarage {
pub motion: Channel<NoopRawMutex, Measurement, 5>,
pub notify: PubSubChannel<CriticalSectionRawMutex, Notification, 5, 2, 4>,
pub predict: Channel<CriticalSectionRawMutex, Prediction, 15>,
pub display: Arc<DisplayControls>
pub telemetry: PubSubChannel<CriticalSectionRawMutex, Telemetry, 15, 2, 4>,
pub display: DisplayControls
}
impl Default for BusGarage {
@@ -142,6 +89,7 @@ impl Default for BusGarage {
motion: Channel::new(),
notify: PubSubChannel::new(),
predict: Channel::new(),
telemetry: PubSubChannel::new(),
display: Default::default()
}
}