use core::slice;
use core::time::Duration;
#[cfg(feature = "alloc")]
extern crate alloc;
use esp_idf_sys::*;
use crate::units::Hertz;
pub use chip::*;
pub use driver::*;
const ERR_ERANGE: esp_err_t = 34;
const ERR_EOVERFLOW: esp_err_t = 139;
pub type RmtTransmitConfig = config::TransmitConfig;
pub type RmtReceiveConfig = config::ReceiveConfig;
#[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
}
}
}
#[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 }
}
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()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PulseTicks(u16);
impl PulseTicks {
const MAX: u16 = 32767;
pub const fn zero() -> Self {
Self(0)
}
pub const fn max() -> Self {
Self(Self::MAX)
}
pub fn new(ticks: u16) -> Result<Self, EspError> {
if ticks > Self::MAX {
Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())
} else {
Ok(Self(ticks))
}
}
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()
}
}
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(ERR_EOVERFLOW).unwrap())?
/ 1_000_000_000;
u16::try_from(ticks).map_err(|_| EspError::from(ERR_EOVERFLOW).unwrap())
}
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(ERR_EOVERFLOW).unwrap())?
/ u32::from(ticks_hz) as u128;
u64::try_from(duration)
.map(Duration::from_nanos)
.map_err(|_| EspError::from(ERR_EOVERFLOW).unwrap())
}
pub type TxRmtConfig = config::TransmitConfig;
pub type RxRmtConfig = config::ReceiveConfig;
pub mod config {
use enumset::EnumSet;
use esp_idf_sys::{EspError, ESP_ERR_INVALID_ARG};
use super::PinState;
use crate::{
interrupt::InterruptType,
units::{FromValueType, Hertz},
};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct DutyPercent(pub(crate) u8);
impl DutyPercent {
pub fn new(v: u8) -> Result<Self, EspError> {
if v > 100 {
Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>())
} else {
Ok(Self(v))
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct CarrierConfig {
pub frequency: Hertz,
pub carrier_level: PinState,
pub duty_percent: DutyPercent,
}
impl CarrierConfig {
pub fn new() -> Self {
Self {
frequency: 38.kHz().into(),
carrier_level: PinState::High,
duty_percent: DutyPercent(33),
}
}
#[must_use]
pub fn frequency(mut self, hz: Hertz) -> Self {
self.frequency = hz;
self
}
#[must_use]
pub fn carrier_level(mut self, state: PinState) -> Self {
self.carrier_level = state;
self
}
#[must_use]
pub fn duty_percent(mut self, duty: DutyPercent) -> Self {
self.duty_percent = duty;
self
}
}
impl Default for CarrierConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Loop {
None,
Endless,
#[cfg(any(
all(not(esp_idf_version_major = "4"), not(esp_idf_version_major = "5")),
all(esp_idf_version_major = "5", not(esp_idf_version_minor = "0")),
not(esp32)
))]
Count(u32),
}
#[derive(Debug, Clone)]
pub struct TransmitConfig {
pub clock_divider: u8,
pub mem_block_num: u8,
pub carrier: Option<CarrierConfig>,
pub looping: Loop,
pub idle: Option<PinState>,
pub aware_dfs: bool,
pub intr_flags: EnumSet<InterruptType>,
}
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),
intr_flags: EnumSet::<InterruptType>::empty(),
}
}
#[must_use]
pub fn aware_dfs(mut self, enable: bool) -> Self {
self.aware_dfs = enable;
self
}
#[must_use]
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
self.mem_block_num = mem_block_num;
self
}
#[must_use]
pub fn clock_divider(mut self, divider: u8) -> Self {
self.clock_divider = divider;
self
}
#[must_use]
pub fn looping(mut self, looping: Loop) -> Self {
self.looping = looping;
self
}
#[must_use]
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
self.carrier = carrier;
self
}
#[must_use]
pub fn idle(mut self, idle: Option<PinState>) -> Self {
self.idle = idle;
self
}
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<InterruptType>) -> Self {
self.intr_flags = flags;
self
}
}
impl Default for TransmitConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
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>,
pub intr_flags: EnumSet<InterruptType>,
}
impl ReceiveConfig {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn clock_divider(mut self, divider: u8) -> Self {
self.clock_divider = divider;
self
}
#[must_use]
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
self.mem_block_num = mem_block_num;
self
}
#[must_use]
pub fn idle_threshold(mut self, threshold: u16) -> Self {
self.idle_threshold = threshold;
self
}
#[must_use]
pub fn filter_ticks_thresh(mut self, threshold: u8) -> Self {
self.filter_ticks_thresh = threshold;
self
}
#[must_use]
pub fn filter_en(mut self, enable: bool) -> Self {
self.filter_en = enable;
self
}
#[must_use]
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
self.carrier = carrier;
self
}
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<InterruptType>) -> Self {
self.intr_flags = flags;
self
}
}
impl Default for ReceiveConfig {
fn default() -> Self {
Self {
clock_divider: 80, mem_block_num: 1, idle_threshold: 12000, filter_ticks_thresh: 100, filter_en: true,
carrier: None,
intr_flags: EnumSet::<InterruptType>::empty(),
}
}
}
}
#[derive(Clone, Copy)]
pub struct Symbol(rmt_item32_t);
impl Symbol {
pub fn new(level0: Pulse, level1: Pulse) -> Self {
let item = rmt_item32_t {
__bindgen_anon_1: rmt_item32_t__bindgen_ty_1 { val: 0 },
};
let mut this = Self(item);
this.update(level0, level1);
this
}
pub fn update(&mut self, level0: Pulse, level1: Pulse) {
let inner = unsafe { &mut self.0.__bindgen_anon_1.__bindgen_anon_1 };
inner.set_level0(level0.pin_state as u32);
inner.set_duration0(level0.ticks.0 as u32);
inner.set_level1(level1.pin_state as u32);
inner.set_duration1(level1.ticks.0 as u32);
}
}
pub trait Signal {
fn as_slice(&self) -> &[rmt_item32_t];
}
impl Signal for Symbol {
fn as_slice(&self) -> &[rmt_item32_t] {
slice::from_ref(&self.0)
}
}
impl Signal for [rmt_item32_t] {
fn as_slice(&self) -> &[rmt_item32_t] {
self
}
}
#[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> {
pub fn new() -> Self {
Self(
[rmt_item32_t {
__bindgen_anon_1: rmt_item32_t__bindgen_ty_1 {
val: 0,
},
}; N],
)
}
pub fn set(&mut self, index: usize, pair: &(Pulse, Pulse)) -> Result<(), EspError> {
let item = self
.0
.get_mut(index)
.ok_or_else(|| EspError::from(ERR_ERANGE).unwrap())?;
let mut symbol = Symbol(*item);
symbol.update(pair.0, pair.1);
*item = symbol.0;
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()
}
}
#[cfg(feature = "alloc")]
#[derive(Clone, Default)]
pub struct VariableLengthSignal {
items: alloc::vec::Vec<rmt_item32_t>,
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,
}
}
pub fn with_capacity(capacity: usize) -> Self {
let vec_size = capacity.div_ceil(2);
Self {
items: alloc::vec::Vec::with_capacity(vec_size),
next_item_is_new: true,
}
}
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 {
let len = self.items.len();
let item = self.items.get_mut(len - 1).unwrap();
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(())
}
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,
}
mod driver {
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::ptr;
use config::{ReceiveConfig, TransmitConfig};
use esp_idf_sys::{
esp, rmt_config_t, rmt_config_t__bindgen_ty_1, rmt_item32_t, rmt_mode_t_RMT_MODE_TX,
rmt_set_tx_loop_mode, rmt_tx_config_t, rmt_tx_stop, vRingbufferReturnItem, EspError,
RMT_CHANNEL_FLAGS_AWARE_DFS,
};
use esp_idf_sys::{rmt_channel_t, rmt_driver_uninstall};
use crate::gpio::{InputPin, OutputPin};
use crate::interrupt::InterruptType;
use super::RmtChannel;
use super::*;
pub struct TxRmtDriver<'d> {
channel: u8,
_p: PhantomData<&'d mut ()>,
}
impl<'d> TxRmtDriver<'d> {
pub fn new<C: RmtChannel + 'd>(
_channel: C,
pin: impl OutputPin + 'd,
config: &TransmitConfig,
) -> Result<Self, EspError> {
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() as _,
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(any(
all(
not(esp_idf_version_major = "4"),
not(esp_idf_version_major = "5")
),
all(esp_idf_version_major = "5", not(esp_idf_version_minor = "0")),
not(esp32)
))]
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,
InterruptType::to_native(config.intr_flags) as _
))?;
}
Ok(Self {
channel: C::channel() as _,
_p: PhantomData,
})
}
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())
}
pub fn start<S>(&mut self, signal: S) -> Result<(), EspError>
where
S: Signal,
{
self.write_items(&signal, false)
}
pub fn start_blocking<S>(&mut self, signal: &S) -> Result<(), EspError>
where
S: Signal + ?Sized,
{
self.write_items(signal, true)
}
fn write_items<S>(&mut self, signal: &S, block: bool) -> Result<(), EspError>
where
S: Signal + ?Sized,
{
let items = signal.as_slice();
esp!(unsafe {
rmt_write_items(self.channel(), items.as_ptr(), items.len() as i32, block)
})
}
#[cfg(feature = "alloc")]
pub fn start_iter<T>(&mut self, iter: T) -> Result<(), EspError>
where
T: Iterator<Item = Symbol> + 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
))
}
}
pub fn start_iter_blocking<T>(&mut self, iter: T) -> Result<(), EspError>
where
T: Iterator<Item = Symbol> + Send,
{
let iter = UnsafeCell::new(iter);
unsafe {
esp!(rmt_translator_init(
self.channel(),
Some(Self::translate_iterator::<T, false>),
))?;
esp!(rmt_write_sample(
self.channel(),
&iter as *const _ as _,
24,
true
))
}
}
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 = Symbol>,
{
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.0;
dest = dest.add(1);
i += 1;
} else {
#[cfg(feature = "alloc")]
if DEALLOC_ITER {
drop(alloc::boxed::Box::from_raw(iter));
}
break src_size;
}
};
*item_num = i;
*translated_size = finished;
}
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 Drop for TxRmtDriver<'_> {
fn drop(&mut self) {
self.stop().unwrap();
esp!(unsafe { rmt_driver_uninstall(self.channel()) }).unwrap();
}
}
unsafe impl Send for TxRmtDriver<'_> {}
pub struct RxRmtDriver<'d> {
channel: u8,
next_ringbuf_item: Option<(*mut rmt_item32_t, usize)>,
_p: PhantomData<&'d mut ()>,
}
impl<'d> RxRmtDriver<'d> {
pub fn new<C: RmtChannel + 'd>(
_channel: C,
pin: impl InputPin + 'd,
config: &ReceiveConfig,
ring_buf_size: usize,
) -> Result<Self, EspError> {
#[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 sys_config = rmt_config_t {
rmt_mode: rmt_mode_t_RMT_MODE_RX,
channel: C::channel(),
gpio_num: pin.pin() as _,
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(&sys_config))?;
esp!(rmt_driver_install(
C::channel(),
ring_buf_size * 4,
InterruptType::to_native(config.intr_flags) as _
))?;
}
Ok(Self {
channel: C::channel() as _,
next_ringbuf_item: None,
_p: PhantomData,
})
}
pub fn channel(&self) -> rmt_channel_t {
self.channel as _
}
pub fn start(&self) -> Result<(), EspError> {
esp!(unsafe { rmt_rx_start(self.channel(), true) })
}
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, _)) = self.next_ringbuf_item.take() {
unsafe {
vRingbufferReturnItem(ringbuf_handle, rmt_items.cast());
}
} else {
unreachable!();
}
Ok(())
}
}
impl Drop for RxRmtDriver<'_> {
fn drop(&mut self) {
self.stop().unwrap();
esp!(unsafe { rmt_driver_uninstall(self.channel()) }).unwrap();
}
}
unsafe impl Send for RxRmtDriver<'_> {}
}
mod chip {
use esp_idf_sys::*;
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
}
}
};
}
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<'static>,
pub channel1: CHANNEL1<'static>,
pub channel2: CHANNEL2<'static>,
pub channel3: CHANNEL3<'static>,
#[cfg(any(esp32, esp32s3))]
pub channel4: CHANNEL4<'static>,
#[cfg(any(esp32, esp32s3))]
pub channel5: CHANNEL5<'static>,
#[cfg(any(esp32, esp32s3))]
pub channel6: CHANNEL6<'static>,
#[cfg(any(esp32, esp32s3))]
pub channel7: CHANNEL7<'static>,
}
impl RMT {
pub(crate) unsafe fn new() -> Self {
Self {
channel0: CHANNEL0::steal(),
channel1: CHANNEL1::steal(),
channel2: CHANNEL2::steal(),
channel3: CHANNEL3::steal(),
#[cfg(any(esp32, esp32s3))]
channel4: CHANNEL4::steal(),
#[cfg(any(esp32, esp32s3))]
channel5: CHANNEL5::steal(),
#[cfg(any(esp32, esp32s3))]
channel6: CHANNEL6::steal(),
#[cfg(any(esp32, esp32s3))]
channel7: CHANNEL7::steal(),
}
}
}
}