src: implement simulation data sources
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use esp_hal::{gpio::AnyPin, rmt::ChannelCreator, Async};
|
||||
use esp_hal::{gpio::AnyPin, rmt::Rmt, time::Rate};
|
||||
use esp_hal_smartled::{buffer_size_async, SmartLedsAdapterAsync};
|
||||
use figments::{hardware::{Brightness, Output}, prelude::Hsv, surface::{BufferedSurfacePool, Surfaces}};
|
||||
use figments::{hardware::{Brightness, OutputAsync}, prelude::Hsv, surface::{BufferedSurfacePool, Surfaces}};
|
||||
use log::{info, warn};
|
||||
use rgb::Rgba;
|
||||
use nalgebra::ComplexField;
|
||||
|
||||
use crate::{display::{BikeOutput, BikeSpace}, events::DisplayControls};
|
||||
use crate::{display::{BikeOutputAsync, BikeSpace}, events::DisplayControls};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Uniforms {
|
||||
@@ -16,9 +17,15 @@ pub struct Uniforms {
|
||||
//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) {
|
||||
pub async fn render(rmt: esp_hal::peripherals::RMT<'static>, gpio: AnyPin<'static>, surfaces: BufferedSurfacePool<Uniforms, BikeSpace, Rgba<u8>>, controls: &'static DisplayControls) {
|
||||
let frequency: Rate = Rate::from_mhz(80);
|
||||
let rmt = Rmt::new(rmt, frequency)
|
||||
.expect("Failed to initialize RMT").into_async();
|
||||
let rmt_channel = rmt.channel0;
|
||||
|
||||
let rmt_buffer = [0u32; buffer_size_async(178)];
|
||||
|
||||
//let target = SmartLedsAdapterAsync::new(rmt_channel, gpio, rmt_buffer);
|
||||
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
|
||||
@@ -29,16 +36,22 @@ pub async fn render(rmt_channel: ChannelCreator<Async, 0>, gpio: AnyPin<'static>
|
||||
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 uniforms = Uniforms {
|
||||
primary_color: Hsv::new(210, 255, 255),
|
||||
..Uniforms::default()
|
||||
};
|
||||
|
||||
let mut output = BikeOutput::new(target, MAX_POWER_MW);
|
||||
let mut output = BikeOutputAsync::new(target, MAX_POWER_MW);
|
||||
|
||||
info!("Rendering started!");
|
||||
info!("Rendering started! {}ms since boot", Instant::now().as_millis());
|
||||
controls.render_is_running.signal(true);
|
||||
|
||||
const FPS: u64 = 60;
|
||||
const RENDER_BUDGET: Duration = Duration::from_millis(1000 / FPS);
|
||||
|
||||
loop {
|
||||
let start = Instant::now();
|
||||
//pixbuf.blank();
|
||||
output.blank().await.expect("Failed to blank framebuf");
|
||||
output.blank_async().await.expect("Failed to blank framebuf");
|
||||
|
||||
surfaces.render_to(&mut output, &uniforms);
|
||||
|
||||
@@ -47,19 +60,19 @@ pub async fn render(rmt_channel: ChannelCreator<Async, 0>, gpio: AnyPin<'static>
|
||||
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");
|
||||
output.commit_async().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;
|
||||
if render_duration < RENDER_BUDGET {
|
||||
let remaining_budget = RENDER_BUDGET - render_duration;
|
||||
uniforms.frame += 1;
|
||||
Timer::after(remaining_budget).await;
|
||||
} else {
|
||||
warn!("Render stall! Frame took {}ms", render_duration.as_millis());
|
||||
let dropped_count = (render_duration.as_ticks() as f32 / RENDER_BUDGET.as_ticks() as f32).ceil() as usize;
|
||||
warn!("Render stall! Frame took {}ms, dropping {dropped_count} frame(s)", render_duration.as_millis());
|
||||
// If we took longer than the budget, we need to drop some frames to catch up
|
||||
uniforms.frame += dropped_count;
|
||||
}
|
||||
|
||||
// Increment the frame counter
|
||||
uniforms.frame += 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user