use esp_hal::Async;
use esp_hal::gpio::Level;
use esp_hal::peripherals::GPIO44;
use esp_hal::rmt::{Channel, ConfigError, Error, PulseCode, Tx, TxChannelConfig, TxChannelCreator};
pub use oxstack_ir as protocols;
use oxstack_ir::{Pulse, nec};
use crate::led::RMT_MHZ;
pub const MAX_PULSES: usize = 47;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum IrError {
TooLong,
Rmt(Error),
}
pub struct IrTx<'d> {
ch: Channel<'d, Async, Tx>,
}
impl<'d> IrTx<'d> {
pub fn new(
channel: impl TxChannelCreator<'d, Async>,
pin: GPIO44<'d>,
) -> Result<Self, ConfigError> {
let carrier_ticks = (RMT_MHZ * 1_000_000 / nec::CARRIER_HZ) as u16;
let config = TxChannelConfig::default()
.with_clk_divider(RMT_MHZ as u8) .with_idle_output(true)
.with_idle_output_level(Level::Low)
.with_carrier_modulation(true)
.with_carrier_level(Level::High)
.with_carrier_high(carrier_ticks / 2)
.with_carrier_low(carrier_ticks - carrier_ticks / 2);
Ok(Self {
ch: channel.configure_tx(&config)?.with_pin(pin),
})
}
pub async fn send(&mut self, pulses: &[Pulse]) -> Result<(), IrError> {
if pulses.len() > MAX_PULSES {
return Err(IrError::TooLong);
}
let mut codes = [PulseCode::end_marker(); MAX_PULSES + 1];
for (code, p) in codes.iter_mut().zip(pulses) {
*code = PulseCode::new(Level::High, p.mark_us, Level::Low, p.space_us);
}
self.ch
.transmit(&codes[..=pulses.len()])
.await
.map_err(IrError::Rmt)
}
pub async fn send_nec(&mut self, address: u8, command: u8) -> Result<(), IrError> {
self.send(&nec::encode(address, command)).await
}
}