#![allow(arithmetic_overflow)] use esp_idf_svc::hal::prelude::Peripherals; use ws2812_esp32_rmt_driver::lib_embedded_graphics::{LedPixelStrip, Ws2812DrawTarget}; use embedded_graphics::{ prelude::*, pixelcolor::{Rgb888, RgbColor}, }; use std::thread::sleep; use std::time::Duration; use palette::{Hsv, Srgb}; use palette::convert::{IntoColor, IntoColorUnclamped, FromColorUnclamped}; fn colorToMW(color : impl RgbColor) -> u32 { const gRed_mW : u32 = 16 * 5; //< 16mA @ 5v = 80mW const gGreen_mW : u32 = 11 * 5; //< 11mA @ 5v = 55mW const gBlue_mW : u32 = 15 * 5; //< 15mA @ 5v = 75mW const gDark_mW : u32 = 1 * 5; //< 1mA @ 5v = 5mW let redMW = (color.r() as u32 * gRed_mW).wrapping_shr(8); let greenMW = (color.g() as u32 * gGreen_mW).wrapping_shr(8); let blueMW = (color.b() as u32 * gBlue_mW).wrapping_shr(8); return redMW + greenMW + blueMW + gDark_mW; } fn brightnessForMW(totalMW : u32, target : u8, maxPower: u32) -> u8 { let target32 = target as u32; let requestedMW = (totalMW * target32) / 256; if requestedMW > maxPower { return ((target32 * maxPower) / requestedMW).try_into().unwrap(); } return target; } #[derive(PartialEq, Debug)] struct RGB8 { red: u8, green: u8, blue: u8 } impl RGB8 { fn new(red : u8, green : u8, blue : u8) -> Self { Self { red: red, green: green, blue: blue } } } impl FromColorUnclamped> for RGB8 { fn from_color_unclamped(hsv: Hsv) -> RGB8 { if hsv.saturation == 0 { return RGB8::new(hsv.value, hsv.value, hsv.value); } let region = hsv.hue.into_inner() / 43; let remainder = (hsv.hue.into_inner() - (region * 43)) * 6; let p = (hsv.value.wrapping_mul(255 - hsv.saturation).wrapping_shr(8)); let q = (hsv.value.wrapping_mul(255 - ((hsv.saturation.wrapping_mul(remainder)).wrapping_shr(8)))).wrapping_shr(8); let t = (hsv.value.wrapping_mul(255 - ((hsv.saturation.wrapping_mul(255 - remainder)).wrapping_shr(8)))).wrapping_shr(8); match region { 0 => RGB8::new(hsv.value, t, p), 1 => RGB8::new(q, hsv.value, p), 2 => RGB8::new(p, hsv.value, t), 3 => RGB8::new(p, q, hsv.value), 4 => RGB8::new(t, p, hsv.value), _ => RGB8::new(hsv.value, p, q) } } } 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 MAX_POWER_MW : u32 = 1000; let mut draw = Ws2812DrawTarget::>::new(channel, led_pin).unwrap(); let mut hue : u8 = 0; let mut length : usize = NUM_PIXELS; let mut forwards = false; loop { let mut totalMW = 0; draw.clear(Rgb888::BLACK); for i in 0..length { //let color = HSV::new(hue.wrapping_add(i as u8), 255, 255); let hsvColor = Hsv::new_srgb(hue.wrapping_add(i as u8), 255, 255); let rgbColor : RGB8 = hsvColor.into_color_unclamped(); //let rgbColor : Srgb = hsvColor.into_color(); let color = Rgb888::new(rgbColor.red, rgbColor.green, rgbColor.blue); totalMW += colorToMW(color); Pixel(Point::new(i as i32, 0), color).draw(&mut draw).unwrap(); } let brightness = brightnessForMW(totalMW, 255, MAX_POWER_MW); draw.set_brightness(brightness); draw.flush().unwrap(); log::info!("Frame hue={} power={} brightness={}", hue, totalMW, brightness); hue = hue.wrapping_add(1); if forwards { length += 1 } else { length -= 1 } if length <= 1 { forwards = true; } else if length >= NUM_PIXELS { forwards = false; } } }