use core::ffi::c_void;
use core::mem::{size_of, MaybeUninit};
use crate::kernel::stream_buffer::{
sbTYPE_STREAM_BUFFER, xStreamBufferBytesAvailable, xStreamBufferGenericCreateStatic,
xStreamBufferIsEmpty, xStreamBufferIsFull, xStreamBufferReceive, xStreamBufferReset,
xStreamBufferSend, xStreamBufferSpacesAvailable, StaticStreamBuffer_t, StreamBufferHandle_t,
};
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::kernel::stream_buffer::xStreamBufferCreate;
use crate::types::*;
pub struct StreamBuffer {
handle: StreamBufferHandle_t,
}
unsafe impl Sync for StreamBuffer {}
unsafe impl Send for StreamBuffer {}
impl StreamBuffer {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub fn new(size: usize, trigger_level: usize) -> Option<Self> {
let handle = unsafe { xStreamBufferCreate(size, trigger_level) };
if handle.is_null() {
None
} else {
Some(Self { handle })
}
}
pub fn new_static(
storage: &'static mut [u8],
trigger_level: usize,
stream_buffer: &'static mut StaticStreamBuffer_t,
) -> Option<Self> {
let handle = unsafe {
xStreamBufferGenericCreateStatic(
storage.len(),
trigger_level,
sbTYPE_STREAM_BUFFER,
storage.as_mut_ptr(),
stream_buffer as *mut StaticStreamBuffer_t,
None,
None,
)
};
if handle.is_null() {
None
} else {
Some(Self { handle })
}
}
pub fn send(&self, data: &[u8]) -> usize {
self.send_timeout(data, portMAX_DELAY)
}
pub fn try_send(&self, data: &[u8]) -> usize {
self.send_timeout(data, 0)
}
pub fn send_timeout(&self, data: &[u8], ticks: TickType_t) -> usize {
if data.is_empty() {
return 0;
}
unsafe {
xStreamBufferSend(
self.handle,
data.as_ptr() as *const c_void,
data.len(),
ticks,
)
}
}
pub fn receive(&self, buf: &mut [u8]) -> usize {
self.receive_timeout(buf, portMAX_DELAY)
}
pub fn try_receive(&self, buf: &mut [u8]) -> usize {
self.receive_timeout(buf, 0)
}
pub fn receive_timeout(&self, buf: &mut [u8], ticks: TickType_t) -> usize {
if buf.is_empty() {
return 0;
}
unsafe {
xStreamBufferReceive(
self.handle,
buf.as_mut_ptr() as *mut c_void,
buf.len(),
ticks,
)
}
}
pub fn send_val<T: Copy>(&self, value: &T) -> bool {
self.send_val_timeout(value, portMAX_DELAY)
}
pub fn try_send_val<T: Copy>(&self, value: &T) -> bool {
self.send_val_timeout(value, 0)
}
pub fn send_val_timeout<T: Copy>(&self, value: &T, ticks: TickType_t) -> bool {
let data =
unsafe { core::slice::from_raw_parts(value as *const T as *const u8, size_of::<T>()) };
self.send_timeout(data, ticks) == size_of::<T>()
}
pub fn receive_val<T: Copy>(&self) -> Option<T> {
self.receive_val_timeout(portMAX_DELAY)
}
pub fn try_receive_val<T: Copy>(&self) -> Option<T> {
self.receive_val_timeout(0)
}
pub fn receive_val_timeout<T: Copy>(&self, ticks: TickType_t) -> Option<T> {
let mut value = MaybeUninit::<T>::uninit();
let received = unsafe {
xStreamBufferReceive(
self.handle,
value.as_mut_ptr() as *mut c_void,
size_of::<T>(),
ticks,
)
};
if received == size_of::<T>() {
Some(unsafe { value.assume_init() })
} else {
None
}
}
pub fn available(&self) -> usize {
unsafe { xStreamBufferBytesAvailable(self.handle) }
}
pub fn spaces(&self) -> usize {
unsafe { xStreamBufferSpacesAvailable(self.handle) }
}
pub fn is_empty(&self) -> bool {
unsafe { xStreamBufferIsEmpty(self.handle) != pdFALSE }
}
pub fn is_full(&self) -> bool {
unsafe { xStreamBufferIsFull(self.handle) != pdFALSE }
}
pub fn reset(&self) -> bool {
unsafe { xStreamBufferReset(self.handle) == pdPASS }
}
pub unsafe fn raw_handle(&self) -> StreamBufferHandle_t {
self.handle
}
}