use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem::{size_of, MaybeUninit};
use crate::kernel::queue::{
queueQUEUE_TYPE_BASE, queueSEND_TO_BACK, queueSEND_TO_FRONT, xQueueGenericCreateStatic,
xQueueGenericSend, xQueuePeek, xQueueReceive, QueueHandle_t, StaticQueue_t,
};
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::kernel::queue::xQueueGenericCreate;
use crate::types::*;
pub struct Queue<T: Copy> {
handle: QueueHandle_t,
_marker: PhantomData<T>,
}
unsafe impl<T: Copy + Send> Sync for Queue<T> {}
unsafe impl<T: Copy + Send> Send for Queue<T> {}
impl<T: Copy> Queue<T> {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub fn new(length: usize) -> Option<Self> {
let item_size = size_of::<T>() as UBaseType_t;
let handle =
unsafe { xQueueGenericCreate(length as UBaseType_t, item_size, queueQUEUE_TYPE_BASE) };
if handle.is_null() {
None
} else {
Some(Self {
handle,
_marker: PhantomData,
})
}
}
pub fn new_static(
storage: &'static mut [T],
queue_buffer: &'static mut StaticQueue_t,
) -> Option<Self> {
let length = storage.len();
let item_size = size_of::<T>();
let handle = unsafe {
xQueueGenericCreateStatic(
length as UBaseType_t,
item_size as UBaseType_t,
storage.as_mut_ptr() as *mut u8,
queue_buffer as *mut StaticQueue_t,
queueQUEUE_TYPE_BASE,
)
};
if handle.is_null() {
None
} else {
Some(Self {
handle,
_marker: PhantomData,
})
}
}
pub fn send(&self, item: &T) -> bool {
self.send_timeout(item, portMAX_DELAY)
}
pub fn try_send(&self, item: &T) -> bool {
self.send_timeout(item, 0)
}
pub fn send_timeout(&self, item: &T, ticks: TickType_t) -> bool {
unsafe {
xQueueGenericSend(
self.handle,
item as *const T as *const c_void,
ticks,
queueSEND_TO_BACK,
) == pdTRUE
}
}
pub fn send_to_front(&self, item: &T) -> bool {
self.send_to_front_timeout(item, portMAX_DELAY)
}
pub fn send_to_front_timeout(&self, item: &T, ticks: TickType_t) -> bool {
unsafe {
xQueueGenericSend(
self.handle,
item as *const T as *const c_void,
ticks,
queueSEND_TO_FRONT,
) == pdTRUE
}
}
pub fn receive(&self) -> Option<T> {
self.receive_timeout(portMAX_DELAY)
}
pub fn try_receive(&self) -> Option<T> {
self.receive_timeout(0)
}
pub fn receive_timeout(&self, ticks: TickType_t) -> Option<T> {
let mut item = MaybeUninit::<T>::uninit();
let result =
unsafe { xQueueReceive(self.handle, item.as_mut_ptr() as *mut c_void, ticks) };
if result == pdTRUE {
Some(unsafe { item.assume_init() })
} else {
None
}
}
pub fn peek(&self) -> Option<T> {
self.peek_timeout(portMAX_DELAY)
}
pub fn try_peek(&self) -> Option<T> {
self.peek_timeout(0)
}
pub fn peek_timeout(&self, ticks: TickType_t) -> Option<T> {
let mut item = MaybeUninit::<T>::uninit();
let result = unsafe { xQueuePeek(self.handle, item.as_mut_ptr() as *mut c_void, ticks) };
if result == pdTRUE {
Some(unsafe { item.assume_init() })
} else {
None
}
}
pub fn len(&self) -> usize {
unsafe { crate::kernel::queue::uxQueueMessagesWaiting(self.handle) as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn available(&self) -> usize {
unsafe { crate::kernel::queue::uxQueueSpacesAvailable(self.handle) as usize }
}
pub fn is_full(&self) -> bool {
self.available() == 0
}
pub fn reset(&self) {
unsafe {
crate::kernel::queue::xQueueGenericReset(self.handle, pdFALSE);
}
}
pub unsafe fn raw_handle(&self) -> QueueHandle_t {
self.handle
}
}