use embedded_graphics::{ prelude::*, pixelcolor::Rgb888, primitives::Rectangle }; use embedded_graphics::pixelcolor::RgbColor; use ws2812_esp32_rmt_driver::lib_embedded_graphics::{Ws2812DrawTarget, LedPixelShape}; use running_average::RealTimeRunningAverage; use std::io; use crate::power; use crate::power::AsMilliwatts; use crate::lib8::*; use crate::render::*; use crate::time::Periodically; use crate::task::Task; use crate::geometry::*; impl AsMilliwatts for T { fn as_milliwatts(&self) -> u32 { const RED_MW : u32 = 16 * 5; //< 16mA @ 5v = 80mW const GREEN_MW : u32 = 11 * 5; //< 11mA @ 5v = 55mW const BLUE_MW : u32 = 15 * 5; //< 15mA @ 5v = 75mW const DARK_MW : u32 = 1 * 5; //< 1mA @ 5v = 5mW let red = (self.r() as u32 * RED_MW).wrapping_shr(8); let green = (self.g() as u32 * GREEN_MW).wrapping_shr(8); let blue = (self.b() as u32 * BLUE_MW).wrapping_shr(8); return red + green + blue + DARK_MW; } } pub struct EmbeddedDisplay where T: DrawTarget, S: Surface { surfaces : SurfacePool, 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 EmbeddedDisplay where T: DrawTarget, S: Surface { pub fn new(target: T, max_mw: u32) -> Self { EmbeddedDisplay { surfaces: SurfacePool::new(), target: target, max_mw: max_mw, total_mw: 0, fps: RealTimeRunningAverage::default(), frame: 0, fps_display: Periodically::new_every_n_seconds(5) } } } impl Surfaces for EmbeddedDisplay where T: DrawTarget, S: Surface { fn new_surface(&mut self) -> Result { self.surfaces.new_surface() } } impl Display for EmbeddedDisplay, S> { fn start_frame(&mut self) { self.total_mw = 0; self.frame = self.frame.wrapping_add(1); } fn end_frame(&mut self) { let brightness = power::brightness_for_mw(self.total_mw, 255, self.max_mw); self.target.set_brightness(brightness); self.target.flush().unwrap(); self.fps.insert(1); self.fps_display.run(|| { log::info!("FPS: {} frame={} brightness={} mw={}", self.fps.measurement(), self.frame, brightness, self.total_mw); }); } fn render_frame(&mut self) { let size = T::size(); let xStride: u8 = 255 / (size.width as u8); let yStride: u8 = 255 / (size.height as u8); let area = Rectangle::new(Point::new(0, 0), size); self.target.draw_iter( area.points() .map(|pos| { let virtCoords = VirtualCoordinates::new(pos.x as u8 * xStride, pos.y as u8 * yStride); let mut pixel = RGB8::new(0, 0, 0); for surface in self.surfaces.iter() { surface.with_shader(|shader| { pixel = shader.draw(virtCoords.clone()); }) } self.total_mw += pixel.as_milliwatts(); return Pixel(pos, Rgb888::new(pixel.red, pixel.green, pixel.blue)); }) ).unwrap(); } }