diff --git a/src/main.rs b/src/main.rs index 176fc87..caee73a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,8 @@ use crate::render::SharedSurface as SurfaceType; #[cfg(not(feature="threads"))] use crate::render::SimpleSurface as SurfaceType; +use crate::render::Renderer; + fn main() { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 @@ -40,13 +42,17 @@ fn main() { let mut display = DisplayType::new_display::(); + log::info!("Created new display type {}", core::any::type_name_of_val(&display)); + log::info!("Creating runner"); let mut runner = task::Scheduler::new(vec![ Box::new(animations::IdleTask::new(display.new_surface().unwrap())), Box::new(animations::TestPattern::new(display.new_surface().unwrap())), - Box::new(display), + Box::new(Renderer::new(display)), ]); + log::info!("Runner ready: {:?}", runner); + log::info!("Ready to rock and roll"); loop { runner.tick(); diff --git a/src/platform/embedded_graphics_lib.rs b/src/platform/embedded_graphics_lib.rs index eb20bfb..22d7962 100644 --- a/src/platform/embedded_graphics_lib.rs +++ b/src/platform/embedded_graphics_lib.rs @@ -8,15 +8,13 @@ use ws2812_esp32_rmt_driver::lib_embedded_graphics::{Ws2812DrawTarget, LedPixelS use esp_idf_svc::hal::prelude::Peripherals; -use running_average::RealTimeRunningAverage; use std::io; +use std::fmt::{Formatter, Debug}; use crate::power; use crate::power::AsMilliwatts; use crate::lib8::*; use crate::render::*; -use crate::time::Periodically; -use crate::task::Task; use crate::geometry::*; use crate::platform::DisplayInit; @@ -28,42 +26,44 @@ S: Surface { target: T, total_mw: u32, max_mw: u32, - fps: RealTimeRunningAverage, - frame: u32, - fps_display: Periodically } -impl Task for EmbeddedDisplay, S> { - fn start(&mut self) { - self.target.set_brightness(0); - } - fn name(&self) -> &'static str { "Renderer" } - - fn tick(&mut self) { - self.start_frame(); - self.render_frame(); - self.end_frame(); +impl Debug for EmbeddedDisplay { + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + f.debug_struct("EmbeddedDisplay") + .field("total_mw", &self.total_mw) + .field("surfaces", &self.surfaces) + .finish() } } +trait TargetInit { + fn setup_target(mut target: T) -> T { target } +} + impl EmbeddedDisplay where +Self: TargetInit, T: DrawTarget, S: Surface { pub fn new(target: T, max_mw: u32) -> Self { EmbeddedDisplay { surfaces: SurfacePool::new(), - target: target, + target: Self::setup_target(target), max_mw: max_mw, total_mw: 0, - fps: RealTimeRunningAverage::default(), - frame: 0, - fps_display: Periodically::new_every_n_seconds(5) } } } +impl TargetInit> for EmbeddedDisplay, S> { + fn setup_target(mut target: Ws2812DrawTarget<'_, T>) -> Ws2812DrawTarget<'_, T> { + target.set_brightness(0); + target + } +} + impl Surfaces for EmbeddedDisplay where T: DrawTarget, @@ -77,17 +77,12 @@ impl Display for EmbeddedDisplay Display for EmbeddedDisplay DisplayInit for Ws2812DrawTarget<'_, Shape> { - fn new_display() -> impl Display + Task { + fn new_display() -> impl Display { let peripherals = Peripherals::take().unwrap(); let led_pin = peripherals.pins.gpio14; let channel = peripherals.rmt.channel0; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 1fc3dbd..bde2c86 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -5,8 +5,7 @@ pub mod embedded_graphics_lib; pub mod smart_leds_lib; use crate::render::{Surface, Display}; -use crate::task::Task; pub trait DisplayInit { - fn new_display() -> impl Display + Task; + fn new_display() -> impl Display; } diff --git a/src/platform/smart_leds_lib.rs b/src/platform/smart_leds_lib.rs index 2e70197..f01e1e9 100644 --- a/src/platform/smart_leds_lib.rs +++ b/src/platform/smart_leds_lib.rs @@ -1,12 +1,10 @@ use smart_leds_trait::SmartLedsWrite; -use running_average::RealTimeRunningAverage; use crate::lib8::Rgb8Blend; use crate::render::{Surface, SurfacePool, Display, Surfaces}; -use crate::task::Task; use crate::power::{brightness_for_mw, AsMilliwatts}; -use crate::time::Periodically; use crate::geometry::*; +use std::fmt::{Debug, Formatter}; use smart_leds::brightness; @@ -17,14 +15,20 @@ use rgb::Rgb; pub struct SmartLedDisplay>, S: Surface> { surfaces : SurfacePool, target: T, - fps: RealTimeRunningAverage, - frame: u32, - fps_display: Periodically, pixbuf: [T::Color; 255], total_mw: u32, max_mw: u32 } +impl>, S: Surface> Debug for SmartLedDisplay { + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { + f.debug_struct("SmartLedDisplay") + .field("total_mw", &self.total_mw) + .field("surfaces", &self.surfaces) + .finish() + } +} + impl>, S: Surface> SmartLedDisplay { pub fn new(target: T, max_mw: u32) -> Self { SmartLedDisplay { @@ -32,21 +36,14 @@ impl>, S: Surface> SmartLedDisplay { target: target, max_mw: max_mw, total_mw: 0, - fps: RealTimeRunningAverage::default(), - frame: 0, - fps_display: Periodically::new_every_n_seconds(5), pixbuf: [Rgb::new(0, 0, 0); 255] } } } -impl>, S: Surface> Task for SmartLedDisplay { - fn name(&self) -> &'static str { "Renderer" } - - fn tick(&mut self) { - self.start_frame(); - self.render_frame(); - self.end_frame(); +impl>, S: Surface> AsMilliwatts for SmartLedDisplay { + fn as_milliwatts(&self) -> u32 { + self.total_mw } } @@ -61,16 +58,11 @@ S: Surface { impl>, S: Surface> Display for SmartLedDisplay { fn start_frame(&mut self) { - self.frame = self.frame.wrapping_add(1); self.total_mw = 0; } fn end_frame(&mut self) { - self.fps.insert(1); let b = brightness_for_mw(self.total_mw, 255, self.max_mw); - self.fps_display.run(|| { - log::info!("FPS: {} frame={} brightness={} mw={}", self.fps.measurement(), self.frame, b, self.total_mw); - }); let _ = self.target.write(brightness(self.pixbuf.iter().cloned(), b)); } @@ -95,12 +87,11 @@ pub mod rmt { use ws2812_esp32_rmt_driver::lib_smart_leds::Ws2812Esp32Rmt; use crate::render::{Display, Surface}; - use crate::task::Task; use crate::platform::smart_leds_lib::SmartLedDisplay; use crate::platform::DisplayInit; impl DisplayInit for Ws2812Esp32Rmt<'_> { - fn new_display() -> impl Display + Task { + fn new_display() -> impl Display { let peripherals = Peripherals::take().unwrap(); let led_pin = peripherals.pins.gpio14; let channel = peripherals.rmt.channel0; @@ -113,7 +104,6 @@ pub mod rmt { return SmartLedDisplay::new(target, MAX_POWER_MW); } } - } #[cfg(feature="spi")] diff --git a/src/render.rs b/src/render.rs index f45bdd3..beb3f81 100644 --- a/src/render.rs +++ b/src/render.rs @@ -7,6 +7,10 @@ use rgb::RGB8; use std::sync::{Arc, Mutex}; use crate::geometry::*; +use crate::task::Task; +use crate::time::Periodically; +use running_average::RealTimeRunningAverage; +use std::marker::PhantomData; use std::fmt::Debug; pub trait Shader: Send + Debug { @@ -29,6 +33,39 @@ pub trait Display: Surfaces { fn render_frame(&mut self); } +#[derive(Debug)] +pub struct Renderer, S: Surface> { + display: T, + fps: RealTimeRunningAverage, + fps_display: Periodically, + _sfc: PhantomData +} + +impl, S: Surface> Renderer { + pub fn new(display: T) -> Self { + Self { + display, + fps: RealTimeRunningAverage::default(), + fps_display: Periodically::new_every_n_seconds(5), + _sfc: PhantomData::default() + } + } +} + +impl, S: Surface> Task for Renderer { + fn name(&self) -> &'static str { "Renderer" } + + fn tick(&mut self) { + self.display.start_frame(); + self.display.render_frame(); + self.display.end_frame(); + self.fps.insert(1); + self.fps_display.run(|| { + log::info!("FPS: {} {:?}", self.fps.measurement(), self.display); + }); + } +} + #[derive(Debug)] pub struct ShaderBinding { shader: Option>,