65 lines
2.5 KiB
Rust
65 lines
2.5 KiB
Rust
use embassy_time::{Duration, Instant, Timer};
|
|
use esp_hal::{gpio::AnyPin, rmt::ChannelCreator, Async};
|
|
use esp_hal_smartled::{buffer_size_async, SmartLedsAdapterAsync};
|
|
use figments::{hardware::{Brightness, Output}, prelude::Hsv, surface::{BufferedSurfacePool, Surfaces}};
|
|
use log::{info, warn};
|
|
use rgb::Rgba;
|
|
|
|
use crate::{display::{BikeOutput, BikeSpace}, events::DisplayControls};
|
|
|
|
#[derive(Default)]
|
|
pub struct Uniforms {
|
|
pub frame: usize,
|
|
pub primary_color: Hsv
|
|
}
|
|
|
|
//TODO: Import the bike surfaces from renderbug-prime, somehow make those surfaces into tasks
|
|
|
|
#[embassy_executor::task]
|
|
pub async fn render(rmt_channel: ChannelCreator<Async, 0>, gpio: AnyPin<'static>, surfaces: BufferedSurfacePool<Uniforms, BikeSpace, Rgba<u8>>, controls: &'static DisplayControls) {
|
|
let rmt_buffer = [0u32; buffer_size_async(178)];
|
|
|
|
let target = SmartLedsAdapterAsync::new(rmt_channel, gpio, rmt_buffer);
|
|
|
|
// Change this to adjust the power available; the USB spec says 500ma is the standard limit, but sometimes you can draw more from a power brick
|
|
const POWER_MA : u32 = 500;
|
|
|
|
// You probably don't need to change these values, unless your LED strip is somehow not 5 volts
|
|
const POWER_VOLTS : u32 = 5;
|
|
const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA;
|
|
|
|
// This value is used as the 'seed' for rendering each frame, allowing us to do things like run the animation backwards, frames for double FPS, or even use system uptime for more human-paced animations
|
|
let mut uniforms = Uniforms::default();
|
|
|
|
let mut output = BikeOutput::new(target, MAX_POWER_MW);
|
|
|
|
info!("Rendering started!");
|
|
|
|
loop {
|
|
let start = Instant::now();
|
|
//pixbuf.blank();
|
|
output.blank().await.expect("Failed to blank framebuf");
|
|
|
|
surfaces.render_to(&mut output, &uniforms);
|
|
|
|
// Apply hardware controls
|
|
output.set_on(controls.on.load(core::sync::atomic::Ordering::Relaxed));
|
|
output.set_brightness(controls.brightness.load(core::sync::atomic::Ordering::Relaxed));
|
|
|
|
// Finally, write out the rendered frame
|
|
output.commit().await.expect("Failed to commit frame");
|
|
|
|
let render_duration = Instant::now() - start;
|
|
let render_budget = Duration::from_millis(16);
|
|
|
|
if render_duration < render_budget {
|
|
let remaining_budget = render_budget - render_duration;
|
|
Timer::after(remaining_budget).await;
|
|
} else {
|
|
warn!("Render stall! Frame took {}ms", render_duration.as_millis());
|
|
}
|
|
|
|
// Increment the frame counter
|
|
uniforms.frame += 1;
|
|
}
|
|
} |