#![feature(trait_upcasting)] #![allow(arithmetic_overflow)] use esp_idf_svc::hal::prelude::Peripherals; use ws2812_esp32_rmt_driver::lib_embedded_graphics::{LedPixelStrip, LedPixelShape, LedPixelMatrix, Ws2812DrawTarget}; use embedded_graphics::{ prelude::*, }; use palette::Hsv; use palette::convert::IntoColorUnclamped; use std::thread; mod power; mod lib8; mod render; mod task; mod time; mod geometry; mod embedded_graphics_lib; use crate::time::Periodically; use crate::geometry::{Coordinates, VirtualCoordinates}; use crate::embedded_graphics_lib::EmbeddedDisplay; struct IdleTask { frame: u8, surface: render::Surface, updater: Periodically } struct IdleShader { frame: u8 } impl render::Shader for IdleShader { fn draw(&self, coords: VirtualCoordinates) -> lib8::RGB8 { Hsv::new_srgb(self.frame.wrapping_add(coords.x()).wrapping_add(coords.y()), 255, 255).into_color_unclamped() } } impl IdleTask { fn new(render: &mut dyn render::Display) -> Self { IdleTask { frame: 0, surface: render.new_surface(), updater: Periodically::new_every_n_ms(16) } } } impl task::Task for IdleTask { fn name(&self) -> &'static str { "Idle" } fn tick(&mut self) { self.updater.run(|| { self.frame = self.frame.wrapping_add(1); self.surface.set_shader(Box::new(IdleShader { frame: self.frame })); }) } fn stop(&mut self) { self.surface.clear_shader(); } } struct PonderjarMatrix {} impl LedPixelShape for PonderjarMatrix { fn size() -> Size { Size::new(17, 17) } fn pixel_index(point: Point) -> Option { if (0..Self::size().width as i32).contains(&point.x) && (0..Self::size().height as i32).contains(&point.y) { if point.y % 2 == 0 { Some((point.y as u32 * Self::size().width as u32 + point.x as u32).try_into().unwrap()) } else { Some((point.y as u32 * Self::size().width as u32 - point.x as u32).try_into().unwrap()) } } else { None } } } 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 esp_idf_svc::sys::link_patches(); // Bind the log crate to the ESP Logging facilities esp_idf_svc::log::EspLogger::initialize_default(); log::info!("Hello, world!"); let peripherals = Peripherals::take().unwrap(); let led_pin = peripherals.pins.gpio14; let channel = peripherals.rmt.channel0; const NUM_PIXELS : usize = 255; const POWER_VOLTS : u32 = 5; const POWER_MA : u32 = 500; const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; log::info!("Setting up display"); let mut target = Ws2812DrawTarget::::new(channel, led_pin).unwrap(); target.set_brightness(0); let mut display = EmbeddedDisplay::new(target, MAX_POWER_MW); log::info!("Creating runner"); let mut runner = task::Scheduler::new(vec![ Box::new(IdleTask::new(&mut display)), Box::new(display), ]); log::info!("Ready to rock and roll"); loop { runner.tick(); } }