esp-idf-hal 0.40.1

A Hardware abstraction layer for Espressif's ESP family of microcontrollers based on the ESP-IDF framework.
//! Remote Control (RMT) module driver.
//!
//! The RMT (Remote Control) module driver can be used to send infrared remote control
//! signals. Due to flexibility of RMT module, the driver can also be used to generate or receive
//! many other types of signals.
//!
//! This module is an abstraction around the [IDF RMT](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html)
//! implementation. It is recommended to read before using this module.
//!
//! This is implementation currently supports transmission only.
//!
//! Not supported:
//! * Interrupts.
//! * Receiving.
//! * Change of config after initialisation.
//!
//! # Example
//!
//! ```
//! // Prepare the config.
//! let config = Config::new().clock_divider(1);
//!
//! // Retrieve the output pin and channel from peripherals.
//! let peripherals = Peripherals::take().unwrap();
//! let channel = peripherals.rmt.channel0;
//! let pin = peripherals.pins.gpio18;
//!
//! // Create an RMT transmitter.
//! let tx = TxRmtDriver::new(channel, pin, &config)?;
//!
//! // Prepare signal pulse signal to be sent.
//! let low = Pulse::new(PinState::Low, PulseTicks::new(10)?);
//! let high = Pulse::new(PinState::High, PulseTicks::new(10)?);
//! let mut signal = FixedLengthSignal::<2>::new();
//! signal.set(0, &(low, high))?;
//! signal.set(1, &(high, low))?;
//!
//! // Transmit the signal.
//! tx.start(signal)?;
//!```
//!
//! See the `examples/` folder of this repository for more.
//!
//! # Loading pulses
//! There are two ways of preparing pulse signal. [FixedLengthSignal] and [VariableLengthSignal]. These
//! implement the [Signal] trait.
//!
//! [FixedLengthSignal] lives on the stack and must have the items set in pairs of [Pulse]s. This is
//! due to the internal implementation of RMT, and const generics limitations.
//!
//! [VariableLengthSignal] allows you to use the heap and incrementally add pulse items without knowing the size
//! ahead of time.

use core::cell::UnsafeCell;
use core::convert::{TryFrom, TryInto};
use core::marker::PhantomData;
use core::ptr;
use core::time::Duration;

#[cfg(feature = "alloc")]
extern crate alloc;

use esp_idf_sys::*;

use crate::gpio::InputPin;
use crate::gpio::OutputPin;
use crate::peripheral::Peripheral;
use crate::units::Hertz;

use config::ReceiveConfig;
use config::TransmitConfig;

pub use chip::*;

pub type RmtTransmitConfig = config::TransmitConfig;
pub type RmtReceiveConfig = config::ReceiveConfig;

/// A `Low` (0) or `High` (1) state for a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PinState {
    Low,
    High,
}

impl From<u32> for PinState {
    fn from(state: u32) -> Self {
        if state == 0 {
            Self::Low
        } else {
            Self::High
        }
    }
}

/// A `Pulse` contains a pin state and a tick count, used in creating a [`Signal`].
///
/// The real time duration of a tick depends on the [`Config::clock_divider`] setting.
///
/// You can create a `Pulse` with a [`Duration`] by using [`Pulse::new_with_duration`].
///
/// # Example
/// ```rust
/// # use esp_idf_hal::rmt::PulseTicks;
/// let pulse = Pulse::new(PinState::High, PulseTicks::new(32));
/// ```
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Pulse {
    pub ticks: PulseTicks,
    pub pin_state: PinState,
}

impl Pulse {
    pub const fn zero() -> Self {
        Self::new(PinState::Low, PulseTicks::zero())
    }

    pub const fn new(pin_state: PinState, ticks: PulseTicks) -> Self {
        Pulse { pin_state, ticks }
    }

    /// Create a [`Pulse`] using a [`Duration`].
    ///
    /// The ticks frequency, which depends on the clock divider set on the channel within a
    /// [`Transmit`]. To get the frequency for the `ticks_hz` argument, use [`Transmit::counter_clock()`].
    ///
    /// # Example
    /// ```
    /// # use esp_idf_sys::EspError;
    /// # use esp_idf_hal::gpio::Output;
    /// # use esp_idf_hal::rmt::Channel::Channel0;
    /// # fn example() -> Result<(), EspError> {
    /// # let peripherals = Peripherals::take()?;
    /// # let led = peripherals.pins.gpio18.into_output()?;
    /// # let channel = peripherals.rmt.channel0;
    /// # let config = Config::new()?;
    /// let tx = Transmit::new(led, channel, &config)?;
    /// let ticks_hz = tx.counter_clock()?;
    /// let pulse = Pulse::new_with_duration(ticks_hz, PinState::High, Duration::from_nanos(500))?;
    /// # }
    /// ```
    pub fn new_with_duration(
        ticks_hz: Hertz,
        pin_state: PinState,
        duration: &Duration,
    ) -> Result<Self, EspError> {
        let ticks = PulseTicks::new_with_duration(ticks_hz, duration)?;
        Ok(Self::new(pin_state, ticks))
    }
}

impl Default for Pulse {
    fn default() -> Self {
        Self::zero()
    }
}

/// Number of ticks, restricting the range to 0 to 32,767.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PulseTicks(u16);

impl PulseTicks {
    const MAX: u16 = 32767;

    pub const fn zero() -> Self {
        Self(0)
    }

    /// Use the maximum value of 32767.
    pub const fn max() -> Self {
        Self(Self::MAX)
    }

    /// Needs to be unsigned 15 bits: 0-32767 inclusive, otherwise an [ESP_ERR_INVALID_ARG] is
    /// returned.
    pub fn new(ticks: u16) -> Result<Self, EspError> {
        if ticks > Self::MAX {
            Err(EspError::from(ESP_ERR_INVALID_ARG).unwrap())
        } else {
            Ok(Self(ticks))
        }
    }

    /// Convert a `Duration` into `PulseTicks`.
    ///
    /// See `Pulse::new_with_duration()` for details.
    pub fn new_with_duration(ticks_hz: Hertz, duration: &Duration) -> Result<Self, EspError> {
        Self::new(duration_to_ticks(ticks_hz, duration)?)
    }

    pub fn ticks(&self) -> u16 {
        self.0
    }

    pub fn duration(&self, ticks_hz: Hertz) -> Result<Duration, EspError> {
        ticks_to_duration(ticks_hz, self.ticks())
    }
}

impl Default for PulseTicks {
    fn default() -> Self {
        Self::zero()
    }
}

/// A utility to convert a duration into ticks, depending on the clock ticks.
pub fn duration_to_ticks(ticks_hz: Hertz, duration: &Duration) -> Result<u16, EspError> {
    let ticks = duration
        .as_nanos()
        .checked_mul(u32::from(ticks_hz) as u128)
        .ok_or_else(|| EspError::from(EOVERFLOW as i32).unwrap())?
        / 1_000_000_000;

    u16::try_from(ticks).map_err(|_| EspError::from(EOVERFLOW as i32).unwrap())
}

/// A utility to convert ticks into duration, depending on the clock ticks.
pub fn ticks_to_duration(ticks_hz: Hertz, ticks: u16) -> Result<Duration, EspError> {
    let duration = 1_000_000_000_u128
        .checked_mul(ticks as u128)
        .ok_or_else(|| EspError::from(EOVERFLOW as i32).unwrap())?
        / u32::from(ticks_hz) as u128;

    u64::try_from(duration)
        .map(Duration::from_nanos)
        .map_err(|_| EspError::from(EOVERFLOW as i32).unwrap())
}

pub type TxRmtConfig = config::TransmitConfig;
pub type RxRmtConfig = config::ReceiveConfig;

/// Types used for configuring the [`rmt`][crate::rmt] module.
///
/// [`Config`] is used when creating a [`Transmit`][crate::rmt::Transmit] instance.
///
/// # Example
/// ```
/// # use esp_idf_hal::units::FromValueType;
/// let carrier = CarrierConfig::new()
///     .duty_percent(DutyPercent::new(50)?)
///     .frequency(611.Hz());
///
/// let config = Config::new()
///     .carrier(Some(carrier))
///     .looping(Loop::Endless)
///     .clock_divider(255);
///
/// ```
pub mod config {
    use esp_idf_sys::{EspError, ESP_ERR_INVALID_ARG};

    use super::PinState;
    use crate::units::{FromValueType, Hertz};

    /// A percentage from 0 to 100%, used to specify the duty percentage in [`CarrierConfig`].
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub struct DutyPercent(pub(super) u8);

    impl DutyPercent {
        /// Must be between 0 and 100, otherwise an error is returned.
        pub fn new(v: u8) -> Result<Self, EspError> {
            if v > 100 {
                Err(EspError::from(ESP_ERR_INVALID_ARG).unwrap())
            } else {
                Ok(Self(v))
            }
        }
    }

    /// Configuration for when enabling a carrier frequency.
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub struct CarrierConfig {
        /// Frequency of the carrier in Hz.
        pub frequency: Hertz,

        /// Level of the RMT output, when the carrier is applied.
        pub carrier_level: PinState,

        /// Duty cycle of the carrier signal in percent (%).
        pub duty_percent: DutyPercent,
    }

    impl CarrierConfig {
        pub fn new() -> Self {
            Self {
                frequency: 38.kHz().into(),
                carrier_level: PinState::High,
                duty_percent: DutyPercent(33),
            }
        }

        pub fn frequency(mut self, hz: Hertz) -> Self {
            self.frequency = hz;
            self
        }

        pub fn carrier_level(mut self, state: PinState) -> Self {
            self.carrier_level = state;
            self
        }

        pub fn duty_percent(mut self, duty: DutyPercent) -> Self {
            self.duty_percent = duty;
            self
        }
    }

    impl Default for CarrierConfig {
        /// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
        fn default() -> Self {
            Self::new()
        }
    }

    /// Configuration setting for looping a signal.
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub enum Loop {
        None,
        Endless,
        #[cfg(not(any(esp32, esp32c2)))]
        Count(u32),
    }

    /// Used when creating a [`Transmit`][crate::rmt::Transmit] instance.
    pub struct TransmitConfig {
        pub clock_divider: u8,
        pub mem_block_num: u8,
        pub carrier: Option<CarrierConfig>,
        // TODO: `loop` is taken. Maybe can change to `repeat` even though it doesn't match the IDF.
        pub looping: Loop,

        /// Enable and set the signal level on the output if idle.
        pub idle: Option<PinState>,

        /// Channel can work during APB clock scaling.
        ///
        /// When set, RMT channel will take REF_TICK or XTAL as source clock. The benefit is, RMT
        /// channel can continue work even when APB clock is changing.
        pub aware_dfs: bool,
    }

    impl TransmitConfig {
        pub fn new() -> Self {
            Self {
                aware_dfs: false,
                mem_block_num: 1,
                clock_divider: 80,
                looping: Loop::None,
                carrier: None,
                idle: Some(PinState::Low),
            }
        }

        pub fn aware_dfs(mut self, enable: bool) -> Self {
            self.aware_dfs = enable;
            self
        }

        pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
            self.mem_block_num = mem_block_num;
            self
        }

        pub fn clock_divider(mut self, divider: u8) -> Self {
            self.clock_divider = divider;
            self
        }

        pub fn looping(mut self, looping: Loop) -> Self {
            self.looping = looping;
            self
        }

        pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
            self.carrier = carrier;
            self
        }

        pub fn idle(mut self, idle: Option<PinState>) -> Self {
            self.idle = idle;
            self
        }
    }

    impl Default for TransmitConfig {
        /// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
        fn default() -> Self {
            Self::new()
        }
    }

    /// Used when creating a [`Receive`][crate::rmt::Receive] instance.
    pub struct ReceiveConfig {
        pub clock_divider: u8,
        pub mem_block_num: u8,
        pub idle_threshold: u16,
        pub filter_ticks_thresh: u8,
        pub filter_en: bool,
        pub carrier: Option<CarrierConfig>,
    }

    impl ReceiveConfig {
        pub fn new() -> Self {
            Self::default()
        }

        pub fn clock_divider(mut self, divider: u8) -> Self {
            self.clock_divider = divider;
            self
        }

        pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
            self.mem_block_num = mem_block_num;
            self
        }

        pub fn idle_threshold(mut self, threshold: u16) -> Self {
            self.idle_threshold = threshold;
            self
        }

        pub fn filter_ticks_thresh(mut self, threshold: u8) -> Self {
            self.filter_ticks_thresh = threshold;
            self
        }

        pub fn filter_en(mut self, enable: bool) -> Self {
            self.filter_en = enable;
            self
        }

        pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
            self.carrier = carrier;
            self
        }
    }

    impl Default for ReceiveConfig {
        /// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L110>`
        fn default() -> Self {
            Self {
                clock_divider: 80,        // one microsecond clock period
                mem_block_num: 1, // maximum of 448 rmt items can be captured (mem_block_num=0 will have max 512 rmt items)
                idle_threshold: 12000, // 1.2 milliseconds, pulse greater than this will generate interrupt
                filter_ticks_thresh: 100, // 100 microseconds, pulses less than this will be ignored
                filter_en: true,
                carrier: None,
            }
        }
    }
}

/// The RMT transmitter driver.
///
/// Use [`TxRmtDriver::start()`] or [`TxRmtDriver::start_blocking()`] to transmit pulses.
///
/// See the [rmt module][crate::rmt] for more information.

pub struct TxRmtDriver<'d> {
    channel: u8,
    _p: PhantomData<&'d mut ()>,
}

impl<'d> TxRmtDriver<'d> {
    /// Initialise the rmt module with the specified pin, channel and configuration.
    ///
    /// To uninstall the driver just drop it.
    ///
    /// Internally this calls `rmt_config()` and `rmt_driver_install()`.
    pub fn new<C: RmtChannel>(
        _channel: impl Peripheral<P = C> + 'd,
        pin: impl Peripheral<P = impl OutputPin> + 'd,
        config: &TransmitConfig,
    ) -> Result<Self, EspError> {
        crate::into_ref!(pin);

        let mut flags = 0;
        if config.aware_dfs {
            flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
        }

        let carrier_en = config.carrier.is_some();
        let carrier = config.carrier.unwrap_or_default();

        let sys_config = rmt_config_t {
            rmt_mode: rmt_mode_t_RMT_MODE_TX,
            channel: C::channel(),
            gpio_num: pin.pin(),
            clk_div: config.clock_divider,
            mem_block_num: config.mem_block_num,
            flags,
            __bindgen_anon_1: rmt_config_t__bindgen_ty_1 {
                tx_config: rmt_tx_config_t {
                    carrier_en,
                    carrier_freq_hz: carrier.frequency.into(),
                    carrier_level: carrier.carrier_level as u32,
                    carrier_duty_percent: carrier.duty_percent.0,
                    idle_output_en: config.idle.is_some(),
                    idle_level: config.idle.map(|i| i as u32).unwrap_or(0),
                    loop_en: config.looping != config::Loop::None,
                    #[cfg(not(any(esp32, esp32c2)))]
                    loop_count: match config.looping {
                        config::Loop::Count(count) if count > 0 && count < 1024 => count,
                        _ => 0,
                    },
                },
            },
        };

        unsafe {
            esp!(rmt_config(&sys_config))?;
            esp!(rmt_driver_install(C::channel(), 0, 0))?;
        }

        Ok(Self {
            channel: C::channel() as _,
            _p: PhantomData,
        })
    }

    /// Get speed of the channel’s internal counter clock.
    ///
    /// This calls [rmt_get_counter_clock()][rmt_get_counter_clock]
    /// internally. It is used for calculating the number of ticks per second for pulses.
    ///
    /// See [Pulse::new_with_duration()].
    ///
    /// [rmt_get_counter_clock]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html#_CPPv421rmt_get_counter_clock13rmt_channel_tP8uint32_t
    pub fn counter_clock(&self) -> Result<Hertz, EspError> {
        let mut ticks_hz: u32 = 0;
        esp!(unsafe { rmt_get_counter_clock(self.channel(), &mut ticks_hz) })?;
        Ok(ticks_hz.into())
    }

    /// Start sending the given signal without blocking.
    ///
    /// `signal` is captured for safety so that the user can't change the data while transmitting.
    pub fn start<S>(&mut self, signal: S) -> Result<(), EspError>
    where
        S: Signal,
    {
        self.write_items(&signal, false)
    }

    /// Start sending the given signal while blocking.
    pub fn start_blocking<S>(&mut self, signal: &S) -> Result<(), EspError>
    where
        S: Signal,
    {
        self.write_items(signal, true)
    }

    fn write_items<S>(&mut self, signal: &S, block: bool) -> Result<(), EspError>
    where
        S: Signal,
    {
        let items = signal.as_slice();
        esp!(unsafe { rmt_write_items(self.channel(), items.as_ptr(), items.len() as i32, block) })
    }

    /// Transmit all items in `iter` without blocking.
    ///
    /// Note that this requires `iter` to be [`Box`]ed for an allocation free version see [`Self::start_iter_blocking`].
    ///
    /// ### Warning
    ///
    /// Iteration of `iter` happens inside an interrupt handler so beware of side-effects
    /// that don't work in interrupt handlers. Iteration must also be fast so that there
    /// are no time-gaps between successive transmissions where the perhipheral has to
    /// wait for items. This can cause weird behavior and can be counteracted with
    /// increasing [`Config::mem_block_num`] or making iteration more efficient.
    #[cfg(feature = "alloc")]
    pub fn start_iter<T>(&mut self, iter: T) -> Result<(), EspError>
    where
        T: Iterator<Item = rmt_item32_t> + Send + 'static,
    {
        let iter = alloc::boxed::Box::new(UnsafeCell::new(iter));
        unsafe {
            esp!(rmt_translator_init(
                self.channel(),
                Some(Self::translate_iterator::<T, true>),
            ))?;

            esp!(rmt_write_sample(
                self.channel(),
                alloc::boxed::Box::leak(iter) as *const _ as _,
                1,
                false
            ))
        }
    }

    /// Transmit all items in `iter`, blocking until all items are transmitted.
    ///
    /// This method does not require any allocations since the thread is paused until all
    /// items are transmitted. The iterator lives on the stack and will be dropped after
    /// all items are written and before this method returns.
    ///
    /// ### Warning
    ///
    /// Iteration of `iter` happens inside an interrupt handler so beware of side-effects
    /// that don't work in interrupt handlers. Iteration must also be fast so that there
    /// are no time-gaps between successive transmissions where the perhipheral has to
    /// wait for items. This can cause weird behavior and can be counteracted with
    /// increasing [`Config::mem_block_num`] or making iteration more efficient.

    pub fn start_iter_blocking<T>(&mut self, iter: T) -> Result<(), EspError>
    where
        T: Iterator<Item = rmt_item32_t> + Send,
    {
        let iter = UnsafeCell::new(iter);
        unsafe {
            // TODO: maybe use a separate struct so that we don't have to do this when
            // transmitting the same iterator type.
            esp!(rmt_translator_init(
                self.channel(),
                Some(Self::translate_iterator::<T, false>),
            ))?;
            esp!(rmt_write_sample(
                self.channel(),
                &iter as *const _ as _,
                24,
                true
            ))
        }
    }

    /// The translator that turns an iterator into `rmt_item32_t` elements. Most of the
    /// magic happens here.
    ///
    /// The general idea is that we can fill a buffer (`dest`) of `rmt_item32_t` items of
    /// length `wanted_num` with the items that we get from the iterator. Then we can tell
    /// the peripheral driver how many items we filled in by setting `item_num`. The
    /// driver will call this function over-and-over until `translated_size` is equal to
    /// `src_size` so when the iterator returns [`None`] we set `translated_size` to
    /// `src_size` to signal that there are no more items to translate.
    ///
    /// The compiler will generate this function for every different call to
    /// [`Self::start_iter_blocking`] and [`Self::start_iter`] with different iterator
    /// types because of the type parameter. This is done to avoid the double indirection
    /// that we'd have to do when using a trait object since references to trait objects
    /// are fat-pointers (2 `usize` wide) and we only get a narrow pointer (`src`).
    /// Using a trait object has the addional overhead that every call to `Iterator::next`
    /// would also be indirect (through the `vtable`) and couldn't be inlined.
    unsafe extern "C" fn translate_iterator<T, const DEALLOC_ITER: bool>(
        src: *const core::ffi::c_void,
        mut dest: *mut rmt_item32_t,
        src_size: usize,
        wanted_num: usize,
        translated_size: *mut usize,
        item_num: *mut usize,
    ) where
        T: Iterator<Item = rmt_item32_t>,
    {
        // An `UnsafeCell` is needed here because we're casting a `*const` to a `*mut`.
        // Safe because this is the only existing reference.
        let iter = &mut *UnsafeCell::raw_get(src as *const UnsafeCell<T>);

        let mut i = 0;
        let finished = loop {
            if i >= wanted_num {
                break 0;
            }

            if let Some(item) = iter.next() {
                *dest = item;
                dest = dest.add(1);
                i += 1;
            } else {
                // Only deallocate the iter if the const generics argument is `true`
                // otherwise we could be deallocating stack memory.
                #[cfg(feature = "alloc")]
                if DEALLOC_ITER {
                    drop(alloc::boxed::Box::from_raw(iter));
                }
                break src_size;
            }
        };

        *item_num = i;
        *translated_size = finished;
    }

    /// Stop transmitting.
    pub fn stop(&mut self) -> Result<(), EspError> {
        esp!(unsafe { rmt_tx_stop(self.channel()) })
    }

    pub fn set_looping(&mut self, looping: config::Loop) -> Result<(), EspError> {
        esp!(unsafe { rmt_set_tx_loop_mode(self.channel(), looping != config::Loop::None) })?;

        #[cfg(not(any(esp32, esp32c2)))]
        esp!(unsafe {
            rmt_set_tx_loop_count(
                self.channel(),
                match looping {
                    config::Loop::Count(count) if count > 0 && count < 1024 => count,
                    _ => 0,
                },
            )
        })?;

        Ok(())
    }

    pub fn channel(&self) -> rmt_channel_t {
        self.channel as _
    }
}

impl<'d> Drop for TxRmtDriver<'d> {
    /// Stop transmitting and release the driver.
    fn drop(&mut self) {
        self.stop().unwrap();
        esp!(unsafe { rmt_driver_uninstall(self.channel()) }).unwrap();
    }
}

unsafe impl<'d> Send for TxRmtDriver<'d> {}

/// Signal storage for [`Transmit`] in a format ready for the RMT driver.
pub trait Signal {
    fn as_slice(&self) -> &[rmt_item32_t];
}

/// Stack based signal storage for an RMT signal.
///
/// Use this if you know the length of the pulses ahead of time and prefer to use the stack.
///
/// Internally RMT uses pairs of pulses as part of its data structure. This implementation
/// you need to [`set`][FixedLengthSignal::set()] a two [`Pulse`]s for each index.
///
/// ```rust
/// # use esp_idf_hal::rmt::FixedLengthSignal;
/// let p1 = Pulse::new(PinState::High, PulseTicks::new(10));
/// let p2 = Pulse::new(PinState::Low, PulseTicks::new(11));
/// let p3 = Pulse::new(PinState::High, PulseTicks::new(12));
/// let p4 = Pulse::new(PinState::Low, PulseTicks::new(13));
///
/// let mut s = FixedLengthSignal::new();
/// s.set(0, &(p1, p2));
/// s.set(1, &(p3, p4));
/// ```
#[derive(Clone)]
pub struct FixedLengthSignal<const N: usize>([rmt_item32_t; N]);

#[cfg(all(esp_idf_version_major = "4", esp32))]
#[allow(non_camel_case_types)]
type rmt_item32_t__bindgen_ty_1 = rmt_item32_s__bindgen_ty_1;
#[cfg(all(esp_idf_version_major = "4", esp32))]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
type rmt_item32_t__bindgen_ty_1__bindgen_ty_1 = rmt_item32_s__bindgen_ty_1__bindgen_ty_1;

impl<const N: usize> FixedLengthSignal<N> {
    /// Creates a new array of size `<N>`, where the number of pulses is `N * 2`.
    pub fn new() -> Self {
        Self(
            [rmt_item32_t {
                __bindgen_anon_1: rmt_item32_t__bindgen_ty_1 {
                    // Quick way to set all 32 bits to zero, instead of using `__bindgen_anon_1`.
                    val: 0,
                },
            }; N],
        )
    }

    /// Set a pair of [`Pulse`]s at a position in the array.
    pub fn set(&mut self, index: usize, pair: &(Pulse, Pulse)) -> Result<(), EspError> {
        let item = self
            .0
            .get_mut(index)
            .ok_or_else(|| EspError::from(ERANGE as i32).unwrap())?;

        // SAFETY: We're overriding all 32 bits, so it doesn't matter what was here before.
        let inner = unsafe { &mut item.__bindgen_anon_1.__bindgen_anon_1 };
        inner.set_level0(pair.0.pin_state as u32);
        inner.set_duration0(pair.0.ticks.0 as u32);
        inner.set_level1(pair.1.pin_state as u32);
        inner.set_duration1(pair.1.ticks.0 as u32);

        Ok(())
    }
}

impl<const N: usize> Signal for FixedLengthSignal<N> {
    fn as_slice(&self) -> &[rmt_item32_t] {
        &self.0
    }
}

impl<const N: usize> Default for FixedLengthSignal<N> {
    fn default() -> Self {
        Self::new()
    }
}

// TODO: impl<const N: usize> From<&[Pulse; N]> for StackSignal<{ (N + 1) / 2 }> {
// Implementing this caused the compiler to crash!

/// `Vec` heap based storage for an RMT signal.
///
/// Use this for when you don't know the final size of your signal data.
///
/// # Example
/// ```rust
/// let mut signal = VariableLengthSignal::new();
/// signal.push(Pulse::new(PinState::High, PulseTicks::new(10)));
/// signal.push(Pulse::new(PinState::Low, PulseTicks::new(9)));
/// ```

#[cfg(feature = "alloc")]
#[derive(Clone, Default)]
pub struct VariableLengthSignal {
    items: alloc::vec::Vec<rmt_item32_t>,

    // Items contain two pulses. Track if we're adding a new pulse to the first one (true) or if
    // we're changing the second one (false).
    next_item_is_new: bool,
}

#[cfg(feature = "alloc")]
impl VariableLengthSignal {
    pub const fn new() -> Self {
        Self {
            items: alloc::vec::Vec::new(),
            next_item_is_new: true,
        }
    }

    /// Create a new [`VariableLengthSignal`] with a a given capacity. This is
    /// more efficent than not specifying the capacity with `new( )` as the
    /// memory manager only needs to allocate the underlying array once.
    ///
    /// - `capacity` is the number of [`Pulse`]s which can be pushes before reallocating
    pub fn with_capacity(capacity: usize) -> Self {
        // half the size, rounding up, because each entry in the [`Vec`] holds upto 2 pulses each
        let vec_size = (capacity + 1) / 2;
        Self {
            items: alloc::vec::Vec::with_capacity(vec_size),
            next_item_is_new: true,
        }
    }

    /// Add [`Pulse`]s to the end of the signal.
    pub fn push<'p, I>(&mut self, pulses: I) -> Result<(), EspError>
    where
        I: IntoIterator<Item = &'p Pulse>,
    {
        for pulse in pulses {
            if self.next_item_is_new {
                let mut inner_item = rmt_item32_t__bindgen_ty_1__bindgen_ty_1::default();

                inner_item.set_level0(pulse.pin_state as u32);
                inner_item.set_duration0(pulse.ticks.0 as u32);

                let item = rmt_item32_t {
                    __bindgen_anon_1: rmt_item32_t__bindgen_ty_1 {
                        __bindgen_anon_1: inner_item,
                    },
                };

                self.items.push(item);
            } else {
                // There should be at least one item in the vec.
                let len = self.items.len();
                let item = self.items.get_mut(len - 1).unwrap();

                // SAFETY: This item was previously populated with the same union field.
                let inner = unsafe { &mut item.__bindgen_anon_1.__bindgen_anon_1 };

                inner.set_level1(pulse.pin_state as u32);
                inner.set_duration1(pulse.ticks.0 as u32);
            }

            self.next_item_is_new = !self.next_item_is_new;
        }

        Ok(())
    }

    /// Delete all pulses.
    pub fn clear(&mut self) {
        self.next_item_is_new = true;
        self.items.clear();
    }
}

#[cfg(feature = "alloc")]
impl Signal for VariableLengthSignal {
    fn as_slice(&self) -> &[rmt_item32_t] {
        &self.items
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Receive {
    Read(usize),
    Overflow(usize),
    Timeout,
}

/// The RMT receiver.
///
/// Use [`RxRmtDriver::start()`] to receive pulses.
///
/// See the [rmt module][crate::rmt] for more information.
pub struct RxRmtDriver<'d> {
    channel: u8,
    next_ringbuf_item: Option<(*mut rmt_item32_t, usize)>,
    _p: PhantomData<&'d mut ()>,
}

impl<'d> RxRmtDriver<'d> {
    /// Initialise the rmt module with the specified pin, channel and configuration.
    ///
    /// To uninstall the driver just drop it.
    ///
    /// Internally this calls `rmt_config()` and `rmt_driver_install()`.

    pub fn new<C: RmtChannel>(
        _channel: impl Peripheral<P = C> + 'd,
        pin: impl Peripheral<P = impl InputPin> + 'd,
        config: &ReceiveConfig,
        ring_buf_size: usize,
    ) -> Result<Self, EspError> {
        crate::into_ref!(pin);

        #[cfg(not(any(esp32, esp32c2)))]
        let carrier_en = config.carrier.is_some();

        #[cfg(not(any(esp32, esp32c2)))]
        let carrier = config.carrier.unwrap_or_default();

        let config = rmt_config_t {
            rmt_mode: rmt_mode_t_RMT_MODE_RX,
            channel: C::channel(),
            gpio_num: pin.pin(),
            clk_div: config.clock_divider,
            mem_block_num: config.mem_block_num,
            flags: 0,
            __bindgen_anon_1: rmt_config_t__bindgen_ty_1 {
                rx_config: rmt_rx_config_t {
                    idle_threshold: config.idle_threshold,
                    filter_ticks_thresh: config.filter_ticks_thresh,
                    filter_en: config.filter_en,
                    #[cfg(not(any(esp32, esp32c2)))]
                    rm_carrier: carrier_en,
                    #[cfg(not(any(esp32, esp32c2)))]
                    carrier_freq_hz: carrier.frequency.into(),
                    #[cfg(not(any(esp32, esp32c2)))]
                    carrier_level: carrier.carrier_level as u32,
                    #[cfg(not(any(esp32, esp32c2)))]
                    carrier_duty_percent: carrier.duty_percent.0,
                },
            },
        };

        unsafe {
            esp!(rmt_config(&config))?;
            esp!(rmt_driver_install(C::channel(), ring_buf_size * 4, 0))?;
        }

        Ok(Self {
            channel: C::channel() as _,
            next_ringbuf_item: None,
            _p: PhantomData,
        })
    }

    pub fn channel(&self) -> rmt_channel_t {
        self.channel as _
    }

    /// Start receiving
    pub fn start(&self) -> Result<(), EspError> {
        esp!(unsafe { rmt_rx_start(self.channel(), true) })
    }

    /// Stop receiving
    pub fn stop(&self) -> Result<(), EspError> {
        esp!(unsafe { rmt_rx_stop(self.channel()) })
    }

    pub fn receive(
        &mut self,
        buf: &mut [(Pulse, Pulse)],
        ticks_to_wait: TickType_t,
    ) -> Result<Receive, EspError> {
        if let Some(items) = self.fetch_ringbuf_next_item(ticks_to_wait)? {
            if items.len() <= buf.len() {
                for (index, item) in items.iter().enumerate() {
                    let item = unsafe { item.__bindgen_anon_1.__bindgen_anon_1 };

                    buf[index] = (
                        Pulse::new(
                            item.level0().into(),
                            PulseTicks::new(item.duration0().try_into().unwrap()).unwrap(),
                        ),
                        Pulse::new(
                            item.level1().into(),
                            PulseTicks::new(item.duration1().try_into().unwrap()).unwrap(),
                        ),
                    );
                }

                let len = items.len();

                self.return_ringbuf_item()?;

                Ok(Receive::Read(len))
            } else {
                Ok(Receive::Overflow(items.len()))
            }
        } else {
            Ok(Receive::Timeout)
        }
    }

    fn fetch_ringbuf_next_item(
        &mut self,
        ticks_to_wait: TickType_t,
    ) -> Result<Option<&[rmt_item32_t]>, EspError> {
        if let Some((rmt_items, length)) = self.next_ringbuf_item {
            Ok(Some(unsafe {
                core::slice::from_raw_parts(rmt_items, length)
            }))
        } else {
            let mut ringbuf_handle = ptr::null_mut();
            esp!(unsafe { rmt_get_ringbuf_handle(self.channel(), &mut ringbuf_handle) })?;

            let mut length = 0;
            let rmt_items: *mut rmt_item32_t = unsafe {
                xRingbufferReceive(ringbuf_handle.cast(), &mut length, ticks_to_wait).cast()
            };

            if rmt_items.is_null() {
                Ok(None)
            } else {
                let length = length / 4;
                self.next_ringbuf_item = Some((rmt_items, length));

                Ok(Some(unsafe {
                    core::slice::from_raw_parts(rmt_items, length)
                }))
            }
        }
    }

    fn return_ringbuf_item(&mut self) -> Result<(), EspError> {
        let mut ringbuf_handle = ptr::null_mut();
        esp!(unsafe { rmt_get_ringbuf_handle(self.channel(), &mut ringbuf_handle) })?;

        if let Some((rmt_items, _)) = core::mem::replace(&mut self.next_ringbuf_item, None) {
            unsafe {
                vRingbufferReturnItem(ringbuf_handle, rmt_items.cast());
            }
        } else {
            unreachable!();
        }

        Ok(())
    }
}

impl<'d> Drop for RxRmtDriver<'d> {
    /// Stop receiving and release the driver.
    fn drop(&mut self) {
        self.stop().unwrap();
        esp!(unsafe { rmt_driver_uninstall(self.channel()) }).unwrap();
    }
}

unsafe impl<'d> Send for RxRmtDriver<'d> {}

mod chip {
    use esp_idf_sys::*;

    /// RMT peripheral channel.
    pub trait RmtChannel {
        fn channel() -> rmt_channel_t;
    }

    macro_rules! impl_channel {
        ($instance:ident: $channel:expr) => {
            crate::impl_peripheral!($instance);

            impl RmtChannel for $instance {
                fn channel() -> rmt_channel_t {
                    $channel
                }
            }
        };
    }

    // SOC_RMT_CHANNELS_PER_GROUP defines how many channels there are.

    impl_channel!(CHANNEL0: rmt_channel_t_RMT_CHANNEL_0);
    impl_channel!(CHANNEL1: rmt_channel_t_RMT_CHANNEL_1);
    impl_channel!(CHANNEL2: rmt_channel_t_RMT_CHANNEL_2);
    impl_channel!(CHANNEL3: rmt_channel_t_RMT_CHANNEL_3);
    #[cfg(any(esp32, esp32s3))]
    impl_channel!(CHANNEL4: rmt_channel_t_RMT_CHANNEL_4);
    #[cfg(any(esp32, esp32s3))]
    impl_channel!(CHANNEL5: rmt_channel_t_RMT_CHANNEL_5);
    #[cfg(any(esp32, esp32s3))]
    impl_channel!(CHANNEL6: rmt_channel_t_RMT_CHANNEL_6);
    #[cfg(any(esp32, esp32s3))]
    impl_channel!(CHANNEL7: rmt_channel_t_RMT_CHANNEL_7);

    pub struct RMT {
        pub channel0: CHANNEL0,
        pub channel1: CHANNEL1,
        pub channel2: CHANNEL2,
        pub channel3: CHANNEL3,
        #[cfg(any(esp32, esp32s3))]
        pub channel4: CHANNEL4,
        #[cfg(any(esp32, esp32s3))]
        pub channel5: CHANNEL5,
        #[cfg(any(esp32, esp32s3))]
        pub channel6: CHANNEL6,
        #[cfg(any(esp32, esp32s3))]
        pub channel7: CHANNEL7,
    }

    impl RMT {
        /// Creates a new instance of the RMT peripheral. Typically one wants
        /// to use the instance [`rmt`](crate::peripherals::Peripherals::rmt) from
        /// the device peripherals obtained via
        /// [`peripherals::Peripherals::take()`](crate::peripherals::Peripherals::take()).
        ///
        /// # Safety
        ///
        /// It is safe to instantiate the RMT peripheral exactly one time.
        /// Care has to be taken that this has not already been done elsewhere.
        pub unsafe fn new() -> Self {
            Self {
                channel0: CHANNEL0::new(),
                channel1: CHANNEL1::new(),
                channel2: CHANNEL2::new(),
                channel3: CHANNEL3::new(),
                #[cfg(any(esp32, esp32s3))]
                channel4: CHANNEL4::new(),
                #[cfg(any(esp32, esp32s3))]
                channel5: CHANNEL5::new(),
                #[cfg(any(esp32, esp32s3))]
                channel6: CHANNEL6::new(),
                #[cfg(any(esp32, esp32s3))]
                channel7: CHANNEL7::new(),
            }
        }
    }
}