use core::fmt;
use alloc::vec::Vec;
use alloc::collections::VecDeque;
use esp_idf_sys::{EspError, ESP_ERR_TIMEOUT};
use super::tx_channel::TxChannelDriver;
use crate::rmt::config::TransmitConfig;
use crate::rmt::encoder::{Encoder, EncoderWrapper, RawEncoder};
#[derive(Debug)]
pub(crate) struct EncoderBuffer<E: RawEncoder> {
encoder: E,
buffer: Vec<E::Item>,
}
impl<E: RawEncoder> EncoderBuffer<E> {
pub fn new(encoder: E) -> Self {
Self {
encoder,
buffer: Vec::new(),
}
}
fn update_from_slice(&mut self, signal: &[E::Item]) -> (&mut E, &[E::Item])
where
E::Item: Clone,
{
self.buffer.resize(signal.len(), signal[0].clone());
self.buffer[..signal.len()].clone_from_slice(signal);
(&mut self.encoder, &self.buffer[..signal.len()])
}
}
pub struct TxQueue<'c, 'd, E: Encoder> {
queue: VecDeque<EncoderBuffer<EncoderWrapper<E>>>,
channel: &'c mut TxChannelDriver<'d>,
}
impl<'c, 'd, E: Encoder> TxQueue<'c, 'd, E> {
pub(crate) fn new(
queue: VecDeque<EncoderBuffer<EncoderWrapper<E>>>,
channel: &'c mut TxChannelDriver<'d>,
) -> Self {
assert!(
!queue.is_empty(),
"At least one encoder is required to encode a TxQueue"
);
Self { queue, channel }
}
#[must_use]
pub fn channel(&mut self) -> &mut TxChannelDriver<'d> {
self.channel
}
}
impl<'c, 'd, E: Encoder> TxQueue<'c, 'd, E> {
pub fn push(&mut self, signal: &[E::Item], config: &TransmitConfig) -> Result<(), EspError>
where
E::Item: Clone,
{
assert!(!signal.is_empty(), "Can not send an empty signal");
while self.channel.queue_size() >= self.queue.len() {
if config.queue_non_blocking {
return Err(EspError::from_infallible::<ESP_ERR_TIMEOUT>());
}
crate::task::block_on(self.channel.wait_for_progress());
}
let (next_encoder, buffer) = self
.queue
.front_mut()
.expect("queue should never be empty")
.update_from_slice(signal);
unsafe { self.channel.start_send(next_encoder, buffer, config) }?;
let buffer = self.queue.pop_front().unwrap();
self.queue.push_back(buffer);
Ok(())
}
}
impl<'c, 'd, E: Encoder> Drop for TxQueue<'c, 'd, E> {
fn drop(&mut self) {
let _ = self.channel.wait_all_done(None);
}
}
impl<'c, 'd, E: Encoder> fmt::Debug for TxQueue<'c, 'd, E>
where
E: fmt::Debug,
E::Item: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TxQueue")
.field("queue", &self.queue)
.field("channel", &self.channel)
.finish()
}
}