diff --git a/Cargo.toml b/Cargo.toml index f1bd706..023ff6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf- [dependencies] log = { version = "0.4", default-features = false } esp-idf-svc = { version = "0.49", default-features = false } -ws2812-esp32-rmt-driver = { version = "*", features = ["embedded-graphics-core"]} +ws2812-esp32-rmt-driver = { version = "*", features = ["embedded-graphics-core", "smart-leds-trait"]} embedded-graphics = { version = "0.8.1", features = ["fixed_point", "defmt"] } hsv = "0.1.1" palette = { version = "0.7.6" } diff --git a/src/main.rs b/src/main.rs index b4466f3..4579e17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,8 @@ -#![feature(trait_upcasting)] -#![allow(arithmetic_overflow)] -use ws2812_esp32_rmt_driver::lib_embedded_graphics::{LedPixelShape, Ws2812DrawTarget}; -use embedded_graphics::{ - prelude::*, -}; use palette::Hsv; use palette::convert::IntoColorUnclamped; -use esp_idf_svc::hal::{ - prelude::*, - spi::{config::{Config, DriverConfig}, Dma, SpiDriver, SpiBusDriver}, - gpio::AnyIOPin, -}; +use ws2812_esp32_rmt_driver::lib_smart_leds::Ws2812Esp32Rmt; +use ws2812_esp32_rmt_driver::lib_embedded_graphics::Ws2812DrawTarget; mod power; mod lib8; @@ -21,17 +12,13 @@ mod time; mod geometry; mod embedded_graphics_lib; mod smart_leds_lib; +mod platform; use crate::time::Periodically; use crate::geometry::{Coordinates, VirtualCoordinates}; -use crate::embedded_graphics_lib::EmbeddedDisplay; -use crate::smart_leds_lib::SmartLedDisplay; -use crate::render::{Surfaces, Surface, SimpleSurface, Display}; +use crate::render::{Shader, Surfaces, Surface, SimpleSurface}; use crate::task::Task; - -use ws2812_spi::Ws2812; -use smart_leds_trait::SmartLedsWrite; -use esp_idf_svc::hal::units::MegaHertz; +use crate::platform::{DisplayInit, PonderjarTarget, SPIDisplay}; struct IdleTask { frame: u8, @@ -43,7 +30,7 @@ struct IdleShader { frame: u8 } -impl render::Shader for IdleShader { +impl 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() } @@ -59,7 +46,7 @@ impl IdleTask { } } -impl task::Task for IdleTask { +impl Task for IdleTask { fn name(&self) -> &'static str { "Idle" } fn tick(&mut self) { @@ -74,72 +61,6 @@ impl task::Task for IdleTask { } } -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 - } - } -} - -type PonderjarTarget<'a> = Ws2812DrawTarget<'a, PonderjarMatrix>; - -trait DisplayInit { - fn new_display() -> impl Display + Task; -} - -impl DisplayInit for Ws2812DrawTarget<'_, Shape> { - fn new_display() -> impl Display + Task { - let peripherals = Peripherals::take().unwrap(); - let led_pin = peripherals.pins.gpio14; - let channel = peripherals.rmt.channel0; - - const POWER_VOLTS : u32 = 5; - const POWER_MA : u32 = 500; - const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; - - let target = Self::new(channel, led_pin).unwrap(); - return EmbeddedDisplay::::new(target, MAX_POWER_MW); - } -} - -struct SPIDisplay {} - -impl DisplayInit for SPIDisplay { - fn new_display() -> impl Display + Task { - let peripherals = Peripherals::take().unwrap(); - - let driver = SpiDriver::new_without_sclk( - peripherals.spi2, - peripherals.pins.gpio14, - Option::::None, - &DriverConfig::new().dma(Dma::Auto(512)) - ).unwrap(); - - let cfg = Config::new().baudrate(3_200.kHz().into()); - - let spi = SpiBusDriver::new(driver, &cfg).unwrap(); - - const POWER_VOLTS : u32 = 5; - const POWER_MA : u32 = 500; - const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; - let target = Ws2812::new(spi); - return SmartLedDisplay::new(target, MAX_POWER_MW) - } -} - 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 @@ -150,7 +71,8 @@ fn main() { log::info!("Setting up display"); //let mut display = SPIDisplay::new_display::(); - let mut display = PonderjarTarget::new_display::(); + //let mut display = PonderjarTarget::new_display::(); + let mut display = Ws2812Esp32Rmt::new_display::(); log::info!("Creating runner"); let mut runner = task::Scheduler::new(vec![ diff --git a/src/platform.rs b/src/platform.rs new file mode 100644 index 0000000..c7c730f --- /dev/null +++ b/src/platform.rs @@ -0,0 +1,102 @@ +use esp_idf_svc::hal::{ + prelude::*, + gpio::AnyIOPin, + spi::{ + config::{Config, DriverConfig}, + Dma, + SpiBusDriver, + SpiDriver, + } +}; + +use ws2812_spi::Ws2812; +use ws2812_esp32_rmt_driver::lib_smart_leds::Ws2812Esp32Rmt; +use ws2812_esp32_rmt_driver::lib_embedded_graphics::{LedPixelShape, Ws2812DrawTarget}; + +use embedded_graphics::prelude::{Size, Point}; + +use crate::smart_leds_lib::SmartLedDisplay; +use crate::embedded_graphics_lib::EmbeddedDisplay; + +use crate::render::{Surface, Display}; +use crate::task::Task; + +pub trait DisplayInit { + fn new_display() -> impl Display + Task; +} + +impl DisplayInit for Ws2812Esp32Rmt<'_> { + fn new_display() -> impl Display + Task { + let peripherals = Peripherals::take().unwrap(); + let led_pin = peripherals.pins.gpio14; + let channel = peripherals.rmt.channel0; + + const POWER_VOLTS : u32 = 5; + const POWER_MA : u32 = 500; + const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; + + let target = Self::new(channel, led_pin).unwrap(); + return SmartLedDisplay::new(target, MAX_POWER_MW); + } +} + +impl DisplayInit for Ws2812DrawTarget<'_, Shape> { + fn new_display() -> impl Display + Task { + let peripherals = Peripherals::take().unwrap(); + let led_pin = peripherals.pins.gpio14; + let channel = peripherals.rmt.channel0; + + const POWER_VOLTS : u32 = 5; + const POWER_MA : u32 = 500; + const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; + + let target = Self::new(channel, led_pin).unwrap(); + return EmbeddedDisplay::::new(target, MAX_POWER_MW); + } +} + +pub struct SPIDisplay {} +impl DisplayInit for SPIDisplay { + fn new_display() -> impl Display + Task { + let peripherals = Peripherals::take().unwrap(); + + let driver = SpiDriver::new_without_sclk( + peripherals.spi2, + peripherals.pins.gpio14, + Option::::None, + &DriverConfig::new().dma(Dma::Auto(512)) + ).unwrap(); + + let cfg = Config::new().baudrate(3_200.kHz().into()); + + let spi = SpiBusDriver::new(driver, &cfg).unwrap(); + + const POWER_VOLTS : u32 = 5; + const POWER_MA : u32 = 500; + const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; + let target = Ws2812::new(spi); + return SmartLedDisplay::new(target, MAX_POWER_MW) + } +} + + +pub 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 + } + } +} + +pub type PonderjarTarget<'a> = Ws2812DrawTarget<'a, PonderjarMatrix>; diff --git a/src/smart_leds_lib.rs b/src/smart_leds_lib.rs index 212e3d5..d032a81 100644 --- a/src/smart_leds_lib.rs +++ b/src/smart_leds_lib.rs @@ -76,7 +76,7 @@ impl>, S: Surface> Display for SmartLedDisp } fn render_frame(&mut self) { - for x in (0..self.pixbuf.len()) { + for x in 0..self.pixbuf.len() { let virtCoords = VirtualCoordinates::new(x as u8, 0); let mut pixel = RGB8::new(0, 0, 0); for surface in self.surfaces.iter() {