use anyhow::Result;
use rand::{self, Rng};
use core::time::Duration;
use esp_idf_svc::hal::{
delay::FreeRtos, peripherals::Peripherals,
gpio::OutputPin,
peripheral::Peripheral,
rmt::{config::TransmitConfig, FixedLengthSignal, PinState, Pulse, RmtChannel, TxRmtDriver},
};
fn main() -> Result<()> {
// 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();
let peripherals = Peripherals::take()?;
println!("pin 48");
let led = peripherals.pins.gpio48;
let channel = peripherals.rmt.channel0;
let mut led = WS2812RMT::new(led, channel)?;
let div: u8 = 1;
let mut high = false;
loop {
high = !high;
println!("high: {}", high);
let (r, g, b): (u8, u8, u8) = rand::thread_rng().gen();
let pixel = if high {
rgb::RGB8 {
r: r / div,
g: g / div,
b: b / div,
}
} else {
rgb::RGB8 { r: 0, g: 0, b: 0 }
};
led.set_pixel(pixel)?;
FreeRtos::delay_ms(2000);
}
}
pub use rgb::RGB8;
pub struct WS2812RMT<'a> {
tx_rtm_driver: TxRmtDriver<'a>,
}
impl<'d> WS2812RMT<'d> {
pub fn new(
led: impl Peripheral<P = impl OutputPin> + 'd,
channel: impl Peripheral<P = impl RmtChannel> + 'd,
) -> Result<Self> {
let config = TransmitConfig::new().clock_divider(2);
let tx = TxRmtDriver::new(channel, led, &config)?;
Ok(Self { tx_rtm_driver: tx })
}
pub fn set_pixel(&mut self, rgb: RGB8) -> Result<()> {
let color: u32 = ((rgb.g as u32) << 16) | ((rgb.r as u32) << 8) | rgb.b as u32;
let ticks_hz = self.tx_rtm_driver.counter_clock()?;
let t0h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(350))?;
let t0l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(800))?;
let t1h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(700))?;
let t1l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(600))?;
let mut signal = FixedLengthSignal::<24>::new();
for i in (0..24).rev() {
let p = 2_u32.pow(i);
let bit = p & color != 0;
let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) };
signal.set(23 - i as usize, &(high_pulse, low_pulse))?;
}
self.tx_rtm_driver.start_blocking(&signal)?;
Ok(())
}
}
fn ns(nanos: u64) -> Duration {
Duration::from_nanos(nanos)
}