display: implement power scaling into the display APIs
This commit is contained in:
@@ -3,6 +3,7 @@ use embassy_time::Duration;
|
|||||||
use enum_map::Enum;
|
use enum_map::Enum;
|
||||||
use enumset::EnumSetType;
|
use enumset::EnumSetType;
|
||||||
use figments::liber8tion::interpolate::Fract8;
|
use figments::liber8tion::interpolate::Fract8;
|
||||||
|
use figments_render::power::Milliwatts;
|
||||||
use nalgebra::{Vector2, Vector3};
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
use crate::ego::engine::MotionState;
|
use crate::ego::engine::MotionState;
|
||||||
@@ -38,6 +39,8 @@ pub enum Measurement {
|
|||||||
GPS(Option<Vector2<f64>>),
|
GPS(Option<Vector2<f64>>),
|
||||||
// Accelerometer values in body frame where x=forwards
|
// Accelerometer values in body frame where x=forwards
|
||||||
IMU { accel: Vector3<f32>, gyro: Vector3<f32> },
|
IMU { accel: Vector3<f32>, gyro: Vector3<f32> },
|
||||||
|
// Power status
|
||||||
|
ExternalPower(Milliwatts),
|
||||||
|
|
||||||
// Hardware status updates
|
// Hardware status updates
|
||||||
SensorHardwareStatus(SensorSource, SensorState),
|
SensorHardwareStatus(SensorSource, SensorState),
|
||||||
@@ -73,6 +76,7 @@ pub enum SensorSource {
|
|||||||
// Real hardware
|
// Real hardware
|
||||||
IMU,
|
IMU,
|
||||||
GPS,
|
GPS,
|
||||||
|
ExternalPower,
|
||||||
|
|
||||||
// Connectivity related
|
// Connectivity related
|
||||||
Wifi,
|
Wifi,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal, watch::{Receiver, Watch}};
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal, watch::{Receiver, Watch}};
|
||||||
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
||||||
|
use portable_atomic::AtomicU32;
|
||||||
use core::{fmt::Debug, ops::Mul, sync::atomic::{AtomicBool, AtomicU8}};
|
use core::{fmt::Debug, ops::Mul, sync::atomic::{AtomicBool, AtomicU8}};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
use figments_render::{
|
use figments_render::{
|
||||||
gamma::{GammaCurve, WithGamma}, output::{Brightness, GammaCorrected, Output, OutputAsync}, power::AsMilliwatts, smart_leds::PowerManagedWriter
|
gamma::{GammaCurve, WithGamma}, output::{Brightness, GammaCorrected, Output, OutputAsync}, power::{AsMilliwatts, Milliwatts}, smart_leds::PowerManagedWriter
|
||||||
};
|
};
|
||||||
use smart_leds::{SmartLedsWrite, SmartLedsWriteAsync};
|
use smart_leds::{SmartLedsWrite, SmartLedsWriteAsync};
|
||||||
|
|
||||||
@@ -23,10 +24,10 @@ impl<T, Color> GammaCorrected for BikeOutput<T, Color> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Color: Default + Copy> BikeOutput<T, Color> {
|
impl<T, Color: Default + Copy> BikeOutput<T, Color> {
|
||||||
pub fn new(target: T, max_mw: u32, controls: DisplayControls) -> Self {
|
pub fn new(target: T, controls: DisplayControls) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pixbuf: [Default::default(); NUM_PIXELS],
|
pixbuf: [Default::default(); NUM_PIXELS],
|
||||||
writer: PowerManagedWriter::new(target, max_mw),
|
writer: PowerManagedWriter::new(target, controls.max_power()),
|
||||||
controls
|
controls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +45,7 @@ impl<'a, T: SmartLedsWrite + 'a> Output<'a, SegmentSpace> for BikeOutput<T, T::C
|
|||||||
fn commit(&mut self) -> Result<(), Self::Error> {
|
fn commit(&mut self) -> Result<(), Self::Error> {
|
||||||
self.writer.controls().set_brightness(self.controls.brightness());
|
self.writer.controls().set_brightness(self.controls.brightness());
|
||||||
self.writer.controls().set_on(self.controls.is_on());
|
self.writer.controls().set_on(self.controls.is_on());
|
||||||
|
self.writer.controls().set_max_power(self.controls.max_power());
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
self.writer.write(&self.pixbuf)
|
self.writer.write(&self.pixbuf)
|
||||||
})
|
})
|
||||||
@@ -165,7 +167,8 @@ pub const LOW_POWER_FPS: u8 = 16;
|
|||||||
struct ControlData {
|
struct ControlData {
|
||||||
on: AtomicBool,
|
on: AtomicBool,
|
||||||
brightness: AtomicU8,
|
brightness: AtomicU8,
|
||||||
fps: AtomicU8
|
fps: AtomicU8,
|
||||||
|
max_power_mw: AtomicU32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControlData {
|
impl Default for ControlData {
|
||||||
@@ -173,7 +176,8 @@ impl Default for ControlData {
|
|||||||
Self {
|
Self {
|
||||||
on: AtomicBool::new(true),
|
on: AtomicBool::new(true),
|
||||||
brightness: AtomicU8::new(255),
|
brightness: AtomicU8::new(255),
|
||||||
fps: AtomicU8::new(DEFAULT_FPS)
|
fps: AtomicU8::new(DEFAULT_FPS),
|
||||||
|
max_power_mw: AtomicU32::new(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,6 +233,14 @@ impl DisplayControls {
|
|||||||
while !self.render_run_receiver.changed().await { log::info!("wait for render run") }
|
while !self.render_run_receiver.changed().await { log::info!("wait for render run") }
|
||||||
log::trace!("render says run!");
|
log::trace!("render says run!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_max_power(&mut self, mw: Milliwatts) {
|
||||||
|
self.data.max_power_mw.store(mw.0, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_power(&self) -> Milliwatts {
|
||||||
|
Milliwatts(self.data.max_power_mw.load(core::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GammaCorrected for DisplayControls {
|
impl GammaCorrected for DisplayControls {
|
||||||
@@ -256,6 +268,7 @@ impl core::fmt::Debug for DisplayControls {
|
|||||||
.field("brightness", &self.data.brightness)
|
.field("brightness", &self.data.brightness)
|
||||||
.field("fps", &self.data.fps)
|
.field("fps", &self.data.fps)
|
||||||
.field("render_pause_signaled", &self.display_is_on.signaled())
|
.field("render_pause_signaled", &self.display_is_on.signaled())
|
||||||
|
.field("max_power_mw", &self.data.max_power_mw)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ pub async fn motion_task(src: DynamicReceiver<'static, Measurement>, prediction_
|
|||||||
warn!("Sensor {source:?} reports {state:?}!");
|
warn!("Sensor {source:?} reports {state:?}!");
|
||||||
prediction_sink.publish(Prediction::SensorStatus(source, state)).with_timeout(TIMEOUT).await.expect("Could not update sensor status in time. Is the prediction bus stalled?");
|
prediction_sink.publish(Prediction::SensorStatus(source, state)).with_timeout(TIMEOUT).await.expect("Could not update sensor status in time. Is the prediction bus stalled?");
|
||||||
},
|
},
|
||||||
|
Measurement::ExternalPower(mw) => {
|
||||||
|
info!("Got external power change to {mw:?}");
|
||||||
|
},
|
||||||
Measurement::SimulationProgress(source, duration, pct) => debug!("{source:?} simulation time: {} {} / 255", duration.as_secs(), pct),
|
Measurement::SimulationProgress(source, duration, pct) => debug!("{source:?} simulation time: {} {} / 255", duration.as_secs(), pct),
|
||||||
Measurement::Annotation => ()
|
Measurement::Annotation => ()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ use log::*;
|
|||||||
use crate::graphics::display::NUM_PIXELS;
|
use crate::graphics::display::NUM_PIXELS;
|
||||||
use crate::{graphics::display::{BikeOutput, DisplayControls, Uniforms}, tasks::ui::UiSurfacePool};
|
use crate::{graphics::display::{BikeOutput, DisplayControls, Uniforms}, tasks::ui::UiSurfacePool};
|
||||||
|
|
||||||
const POWER_MA : u32 = 300;
|
|
||||||
const POWER_VOLTS : u32 = 5;
|
|
||||||
const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA;
|
|
||||||
static SPI_BUFFERS: static_cell::ConstStaticCell<DmaBuffers<u8, {NUM_PIXELS * 12 + 140}>> = static_cell::ConstStaticCell::new(DmaBuffers::new(0));
|
static SPI_BUFFERS: static_cell::ConstStaticCell<DmaBuffers<u8, {NUM_PIXELS * 12 + 140}>> = static_cell::ConstStaticCell::new(DmaBuffers::new(0));
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
@@ -40,7 +37,7 @@ pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: An
|
|||||||
..Uniforms::default()
|
..Uniforms::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = BikeOutput::new(target, MAX_POWER_MW, controls.clone());
|
let mut output = BikeOutput::new(target, controls.clone());
|
||||||
output.set_gamma(GammaCurve::new(1.3));
|
output.set_gamma(GammaCurve::new(1.3));
|
||||||
|
|
||||||
info!("Rendering started! {}ms since boot", Instant::now().as_millis());
|
info!("Rendering started! {}ms since boot", Instant::now().as_millis());
|
||||||
|
|||||||
Reference in New Issue
Block a user