use core::ffi::c_void;
use core::{mem, ptr, slice};
use alloc::boxed::Box;
use esp_idf_sys::*;
use crate::rmt::encoder::RawEncoder;
use crate::rmt::Symbol;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NotEnoughSpace;
#[derive(Debug, Clone)]
pub struct SimpleEncoderConfig {
pub min_chunk_size: usize,
#[doc(hidden)]
#[allow(dead_code)]
pub __internal: (),
}
impl Default for SimpleEncoderConfig {
fn default() -> Self {
Self {
min_chunk_size: 64,
__internal: (),
}
}
}
#[derive(Debug)]
pub struct SymbolBuffer<'a> {
symbols: &'a mut [Symbol],
written: usize,
}
impl<'a> SymbolBuffer<'a> {
#[must_use]
pub unsafe fn from_raw_parts(
symbols: *mut rmt_symbol_word_t,
written: usize,
free: usize,
) -> Self {
let symbols = slice::from_raw_parts_mut(symbols as *mut Symbol, written + free);
Self { symbols, written }
}
#[must_use]
pub const fn position(&self) -> usize {
self.written
}
#[must_use]
pub fn remaining(&self) -> usize {
self.symbols.len() - self.written
}
pub fn write_all(&mut self, symbols: &[Symbol]) -> Result<(), NotEnoughSpace> {
if self.remaining() < symbols.len() {
return Err(NotEnoughSpace);
}
for &symbol in symbols {
self.symbols[self.written] = symbol;
self.written += 1;
}
Ok(())
}
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [Symbol] {
&mut self.symbols[..self.written]
}
}
unsafe extern "C" fn delegator<S: EncoderCallback>(
data: *const c_void,
data_size: usize,
symbols_written: usize,
symbols_free: usize,
symbols: *mut rmt_symbol_word_t,
done: *mut bool,
arg: *mut c_void,
) -> usize {
let callback = &mut *(arg as *mut S);
let data_slice = slice::from_raw_parts(
data as *const S::Item,
data_size / mem::size_of::<S::Item>(),
);
let mut buffer = SymbolBuffer::from_raw_parts(symbols, symbols_written, symbols_free);
if let Ok(()) = callback.encode(data_slice, &mut buffer) {
*done = true;
}
buffer.position() - symbols_written
}
pub trait EncoderCallback {
type Item;
fn encode(
&mut self,
input_data: &[Self::Item],
buffer: &mut SymbolBuffer<'_>,
) -> Result<(), NotEnoughSpace>;
}
#[derive(Debug)]
pub struct SimpleEncoder<T> {
_encoder: Box<T>,
handle: rmt_encoder_handle_t,
}
impl<T: EncoderCallback> SimpleEncoder<T> {
pub fn with_config(encoder: T, config: &SimpleEncoderConfig) -> Result<Self, EspError> {
let mut encoder = Box::new(encoder);
let reference = encoder.as_mut();
let sys_config = rmt_simple_encoder_config_t {
callback: Some(delegator::<T>),
arg: reference as *mut T as *mut c_void,
min_chunk_size: config.min_chunk_size,
};
let mut handle: rmt_encoder_handle_t = ptr::null_mut();
esp!(unsafe { rmt_new_simple_encoder(&sys_config, &mut handle) })?;
Ok(Self {
handle,
_encoder: encoder,
})
}
}
impl<T: EncoderCallback> RawEncoder for SimpleEncoder<T> {
type Item = T::Item;
fn handle(&mut self) -> &mut rmt_encoder_t {
unsafe { &mut *self.handle }
}
}
impl<T> Drop for SimpleEncoder<T> {
fn drop(&mut self) {
unsafe { rmt_del_encoder(self.handle) };
}
}