use bbqueue as bbq;
type Producer = bbq::Producer<'static, { crate::BUFFER_SIZE }>;
#[cfg(feature = "lpuart")]
use imxrt_hal::{dma::channel::Channel, lpuart::Lpuart};
mod frontend {
use super::Producer;
use core::{
cell::{Cell, RefCell},
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering},
};
use critical_section::RestoreState;
pub(super) struct Frontend {
init: AtomicBool,
producer: RefCell<MaybeUninit<Producer>>,
restore_state: Cell<RestoreState>,
encoder: RefCell<defmt::Encoder>,
}
unsafe impl Sync for Frontend {}
impl Frontend {
const fn new() -> Self {
Self {
init: AtomicBool::new(false),
producer: RefCell::new(MaybeUninit::uninit()),
restore_state: Cell::new(RestoreState::invalid()),
encoder: RefCell::new(defmt::Encoder::new()),
}
}
pub(super) fn init(&self, producer: Producer) {
*self.producer.borrow_mut() = MaybeUninit::new(producer);
self.init.store(true, Ordering::Release);
}
unsafe fn with_producer_encoder<R>(
&self,
func: impl FnOnce(&mut Producer, &mut defmt::Encoder) -> R,
) -> R {
unsafe {
let mut producer = self.producer.borrow_mut();
let producer = producer.assume_init_mut();
let mut encoder = self.encoder.borrow_mut();
func(producer, &mut encoder)
}
}
pub fn acquire<R>(
&self,
func: impl FnOnce(&mut Producer, &mut defmt::Encoder) -> R,
) -> Option<R> {
self.init.load(Ordering::Acquire).then(|| {
unsafe { self.restore_state.set(critical_section::acquire()) };
unsafe { self.with_producer_encoder(func) }
})
}
pub fn release<R>(
&self,
func: impl FnOnce(&mut Producer, &mut defmt::Encoder) -> R,
) -> Option<R> {
self.init.load(Ordering::Acquire).then(|| {
let result = unsafe { self.with_producer_encoder(func) };
unsafe {
critical_section::release(self.restore_state.replace(RestoreState::invalid()))
};
result
})
}
pub fn write<R>(
&self,
func: impl FnOnce(&mut Producer, &mut defmt::Encoder) -> R,
) -> Option<R> {
self.init.load(Ordering::Acquire).then(|| {
unsafe { self.with_producer_encoder(func) }
})
}
}
pub(super) static FRONTEND: Frontend = Frontend::new();
}
#[defmt::global_logger]
struct Logger;
unsafe impl defmt::Logger for Logger {
fn acquire() {
frontend::FRONTEND.acquire(|producer, encoder| {
encoder.start_frame(|buffer| {
let _ = crate::try_write_producer(buffer, producer);
});
});
}
unsafe fn release() {
frontend::FRONTEND.release(|producer, encoder| {
encoder.end_frame(|buffer| {
let _ = crate::try_write_producer(buffer, producer);
});
});
}
unsafe fn write(bytes: &[u8]) {
frontend::FRONTEND.write(|producer, encoder| {
encoder.write(bytes, |buffer| {
let _ = crate::try_write_producer(buffer, producer);
});
});
}
unsafe fn flush() {
}
}
#[cfg(feature = "usbd")]
pub fn usb_with_config<const N: u8>(
peripherals: imxrt_usbd::Instances<N>,
interrupts: super::Interrupts,
backend_config: &crate::UsbdConfig,
) -> Result<crate::Poller, crate::AlreadySetError<imxrt_usbd::Instances<N>>> {
let (producer, consumer) = match crate::BUFFER.try_split() {
Ok((prod, cons)) => (prod, cons),
Err(_) => return Err(crate::AlreadySetError::new(peripherals)),
};
critical_section::with(|_| {
frontend::FRONTEND.init(producer);
let backend = crate::usbd::init(peripherals, interrupts, consumer, backend_config);
Ok(crate::Poller::new(backend))
})
}
#[cfg(feature = "usbd")]
pub fn usbd<const N: u8>(
peripherals: imxrt_usbd::Instances<N>,
interrupts: super::Interrupts,
) -> Result<crate::Poller, crate::AlreadySetError<imxrt_usbd::Instances<N>>> {
usb_with_config(
peripherals,
interrupts,
&crate::UsbdConfigBuilder::new().build(),
)
}
#[cfg(feature = "lpuart")]
pub fn lpuart(
lpuart: Lpuart,
dma_channel: Channel,
interrupts: crate::Interrupts,
) -> Result<crate::Poller, crate::AlreadySetError<(Lpuart, Channel)>> {
let (producer, consumer) = match crate::BUFFER.try_split() {
Ok((prod, cons)) => (prod, cons),
Err(_) => return Err(crate::AlreadySetError::new((lpuart, dma_channel))),
};
critical_section::with(|_| {
frontend::FRONTEND.init(producer);
let backend = crate::lpuart::init(lpuart, dma_channel, consumer, interrupts);
Ok(crate::Poller::new(backend))
})
}