use smart_leds_trait::SmartLedsWrite; use crate::render::{HardwarePixel, Output, PixelView, Sample}; use crate::power::{brightness_for_mw, AsMilliwatts}; use crate::geometry::*; use crate::mappings::*; use std::fmt::Debug; use std::ops::IndexMut; pub trait Pixbuf: AsMilliwatts + IndexMut { type Pixel: HardwarePixel; fn new() -> Self; fn blank(&mut self); fn iter_with_brightness(&self, brightness: u8) -> impl Iterator + Send; fn pixel_count(&self) -> usize; } struct StrideSampler<'a, P: Pixbuf> { pixbuf: &'a mut P, selection: StrideView<'a> } impl<'a, P: Pixbuf> PixelView for StrideSampler<'a, P> { type Pixel = P::Pixel; fn next(&mut self) -> Option<(Coordinates, &mut Self::Pixel)> { if let Some((virt, coords)) = self.selection.next() { let idx = self.selection.map.strides[coords.x as usize].pixel_idx_for_offset(coords.y); Some((virt, &mut self.pixbuf[idx])) } else { None } } } impl Debug for StrideOutput { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("StrideOutput").finish() } } pub struct StrideOutput { pixbuf: P, stride_map: StrideMapping, target: T, max_mw: u32 } impl StrideOutput { fn new(pixbuf: P, stride_map: StrideMapping, target: T, max_mw: u32) -> Self { assert!(stride_map.pixel_count <= pixbuf.pixel_count(), "map needs {} pixels, I only have PIXEL_NUM={}", stride_map.pixel_count, pixbuf.pixel_count()); StrideOutput { pixbuf, stride_map, target, max_mw } } } impl Sample for StrideOutput { type Pixel = P::Pixel; fn sample(&mut self, rect: &Rectangle) -> impl PixelView { StrideSampler { pixbuf: &mut self.pixbuf, selection: self.stride_map.select(rect) } } } impl, T: FastWrite> Output for StrideOutput { fn blank(&mut self) { self.pixbuf.blank(); } fn commit(&mut self) { let b = brightness_for_mw(self.pixbuf.as_milliwatts(), 255, self.max_mw); if self.target.fast_write(self.pixbuf.iter_with_brightness(b)).is_err() { panic!("Could not write frame!"); }; } } impl Pixbuf for [T; PIXEL_NUM] { type Pixel = T; fn new() -> Self { [T::default(); PIXEL_NUM] } fn pixel_count(&self) -> usize { self.len() } fn blank(&mut self) { self.fill(T::default()) } fn iter_with_brightness(&self, brightness: u8) -> impl Iterator + Send { self.iter().map(move |x| { x.scale8(brightness)}) } } pub trait FastWrite { type Target: SmartLedsWrite; type Color: HardwarePixel; type Error; fn fast_write(&mut self, iterator: T) -> Result<(), Self::Error> where T: IntoIterator, I: Into, ::IntoIter: Send; } #[cfg(feature="rmt")] pub mod rmt { use esp_idf_svc::{hal::prelude::Peripherals, sys::esp_efuse_mac_get_default}; use ws2812_esp32_rmt_driver::driver::color::LedPixelColorGrb24; use smart_leds::SmartLedsWrite; use rgb::Rgb; use ws2812_esp32_rmt_driver::LedPixelEsp32Rmt; use crate::mappings::StrideMapping; use crate::platform::smart_leds_lib::StrideOutput; use crate::render::Surface; use crate::platform::DisplayInit; use super::{Pixbuf, FastWrite}; pub type FastWs2812Esp32Rmt<'a> = LedPixelEsp32Rmt<'a, Rgb, LedPixelColorGrb24>; impl FastWrite for FastWs2812Esp32Rmt<'_> { type Color = ::Color; type Error = ::Error; type Target = Self; fn fast_write(&mut self, iterator: T) -> Result<(), Self::Error> where T: IntoIterator, I: Into, ::IntoIter: Send { self.write_nocopy(iterator) } } impl DisplayInit for FastWs2812Esp32Rmt<'_> { type Output = StrideOutput<[Rgb; 310], Self>; fn new_display() -> Self::Output { const POWER_VOLTS : u32 = 5; const POWER_MA : u32 = 500; const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; let peripherals = Peripherals::take().unwrap(); let channel = peripherals.rmt.channel0; let pins = peripherals.pins; let mut chip_id: [u8; 8] = [0; 8]; unsafe { esp_efuse_mac_get_default(&mut chip_id as *mut u8); } let (pixmap, target) = match chip_id { [72, 202, 67, 89, 145, 204, 0, 0] => { (StrideMapping::new_panel(), Self::new(channel, pins.gpio5).unwrap()) }, [140, 170, 181, 131, 95, 116, 0, 0] => { (StrideMapping::new_jar(), Self::new(channel, pins.gpio14).unwrap()) }, _ => { (StrideMapping::new(), Self::new(channel, pins.gpio5).unwrap()) } }; StrideOutput::new( Pixbuf::new(), pixmap, target, MAX_POWER_MW ) } } } #[cfg(feature="spi")] pub mod spi { use smart_leds::SmartLedsWrite; use ws2812_spi::prerendered::Ws2812; use crate::render::{Display, Surface}; use crate::platform::smart_leds_lib::SmartLedDisplay; use crate::DisplayInit; use super::FastWrite; use esp_idf_svc::hal::{ prelude::*, gpio::AnyIOPin, spi::{ config::{Config, DriverConfig}, Dma, SpiBusDriver, SpiDriver, } }; impl<'a> FastWrite for Ws2812<'_, SpiBusDriver<'a, SpiDriver<'a>>> { type Color = ::Color; type Error = ::Error; type Target = Self; fn fast_write(&mut self, iterator: T) -> Result<(), Self::Error> where T: IntoIterator, I: Into, ::IntoIter: Send { let resp = self.write(iterator); if let Err(e) = resp { panic!("Could not write SPI frame! {:?}", e) } else { resp } } } static mut STATIC_BUFFER: [u8; 400 * 12] = [0; 400 * 12]; pub struct SPIDisplay {} impl DisplayInit for SPIDisplay { fn new_display() -> impl Display { let peripherals = Peripherals::take().unwrap(); let driver = SpiDriver::new_without_sclk( peripherals.spi2, peripherals.pins.gpio5, Option::::None, &DriverConfig::new().dma(Dma::Auto(4092)) ).unwrap(); let cfg = Config::new().baudrate(3.MHz().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; unsafe { let target = Ws2812::new(spi, &mut STATIC_BUFFER); return SmartLedDisplay::>>, S, 310>::new(target, MAX_POWER_MW); } } } }