1use esp_hal::Async;
17use esp_hal::gpio::Level;
18use esp_hal::peripherals::GPIO44;
19use esp_hal::rmt::{Channel, ConfigError, Error, PulseCode, Tx, TxChannelConfig, TxChannelCreator};
20pub use oxstack_ir as protocols;
21use oxstack_ir::{Pulse, nec};
22
23use crate::led::RMT_MHZ;
24
25pub const MAX_PULSES: usize = 47;
28
29#[derive(Debug)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum IrError {
33 TooLong,
35 Rmt(Error),
37}
38
39pub struct IrTx<'d> {
41 ch: Channel<'d, Async, Tx>,
42}
43
44impl<'d> IrTx<'d> {
45 pub fn new(
48 channel: impl TxChannelCreator<'d, Async>,
49 pin: GPIO44<'d>,
50 ) -> Result<Self, ConfigError> {
51 let carrier_ticks = (RMT_MHZ * 1_000_000 / nec::CARRIER_HZ) as u16;
52 let config = TxChannelConfig::default()
53 .with_clk_divider(RMT_MHZ as u8) .with_idle_output(true)
55 .with_idle_output_level(Level::Low)
56 .with_carrier_modulation(true)
57 .with_carrier_level(Level::High)
58 .with_carrier_high(carrier_ticks / 2)
59 .with_carrier_low(carrier_ticks - carrier_ticks / 2);
60 Ok(Self {
61 ch: channel.configure_tx(&config)?.with_pin(pin),
62 })
63 }
64
65 pub async fn send(&mut self, pulses: &[Pulse]) -> Result<(), IrError> {
67 if pulses.len() > MAX_PULSES {
68 return Err(IrError::TooLong);
69 }
70 let mut codes = [PulseCode::end_marker(); MAX_PULSES + 1];
71 for (code, p) in codes.iter_mut().zip(pulses) {
72 *code = PulseCode::new(Level::High, p.mark_us, Level::Low, p.space_us);
74 }
75 self.ch
76 .transmit(&codes[..=pulses.len()])
77 .await
78 .map_err(IrError::Rmt)
79 }
80
81 pub async fn send_nec(&mut self, address: u8, command: u8) -> Result<(), IrError> {
83 self.send(&nec::encode(address, command)).await
84 }
85}