use display_interface::DisplayError; use embassy_time::{Duration, Instant, Timer}; use embedded_graphics::{pixelcolor::BinaryColor, prelude::DrawTarget}; use figments::render::RenderSource; use figments_render::output::OutputAsync; use log::*; use crate::{backoff::Backoff, graphics::ssd1306::SsdOutput, tasks::oled::{LockedUniforms, OledUiSurfacePool}}; #[embassy_executor::task] pub async fn oled_render(mut output: SsdOutput, mut surfaces: OledUiSurfacePool, uniforms: LockedUniforms) { warn!("Starting OLED rendering task"); Backoff::from_secs(1).forever().attempt::<_, (), DisplayError>(async || { const FPS: u64 = 30; const RENDER_BUDGET: Duration = Duration::from_millis(1000 / FPS); const ANIMATION_TPS: u64 = 30; const ANIMATION_FRAME_TIME: Duration = Duration::from_millis(1000 / ANIMATION_TPS); info!("Starting Oled display driver"); output.init().await?; loop { let start = Instant::now(); surfaces.commit(); { let mut locked = uniforms.lock().await; output.clear(BinaryColor::Off).unwrap(); locked.frame = (Instant::now().as_millis() / ANIMATION_FRAME_TIME.as_millis()) as usize; locked.current_screen.render_to(&mut output, &locked); surfaces.render_to(&mut output, &locked); } output.commit_async().await?; let frame_time = Instant::now() - start; if frame_time < RENDER_BUDGET { Timer::after(RENDER_BUDGET - frame_time).await; } else { //warn!("OLED Frame took too long to render! {}ms", frame_time.as_millis()); } } }).await.unwrap(); }