use core::ffi::c_void;
use core::mem::{size_of, MaybeUninit};
use crate::kernel::stream_buffer::{
sbTYPE_MESSAGE_BUFFER, xStreamBufferBytesAvailable, xStreamBufferGenericCreateStatic,
xStreamBufferIsEmpty, xStreamBufferIsFull, xStreamBufferNextMessageLengthBytes,
xStreamBufferReceive, xStreamBufferReset, xStreamBufferSend, xStreamBufferSpacesAvailable,
StaticStreamBuffer_t, StreamBufferHandle_t,
};
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::kernel::stream_buffer::xStreamBufferGenericCreate;
use crate::types::*;
pub struct MessageBuffer {
handle: StreamBufferHandle_t,
}
unsafe impl Sync for MessageBuffer {}
unsafe impl Send for MessageBuffer {}
impl MessageBuffer {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub fn new(size: usize) -> Option<Self> {
let handle =
unsafe { xStreamBufferGenericCreate(size, 1, sbTYPE_MESSAGE_BUFFER, None, None) };
if handle.is_null() {
None
} else {
Some(Self { handle })
}
}
pub fn new_static(
storage: &'static mut [u8],
msg_buffer: &'static mut StaticStreamBuffer_t,
) -> Option<Self> {
let handle = unsafe {
xStreamBufferGenericCreateStatic(
storage.len(),
1, sbTYPE_MESSAGE_BUFFER,
storage.as_mut_ptr(),
msg_buffer as *mut StaticStreamBuffer_t,
None,
None,
)
};
if handle.is_null() {
None
} else {
Some(Self { handle })
}
}
pub fn send(&self, data: &[u8]) -> bool {
self.send_timeout(data, portMAX_DELAY)
}
pub fn try_send(&self, data: &[u8]) -> bool {
self.send_timeout(data, 0)
}
pub fn send_timeout(&self, data: &[u8], ticks: TickType_t) -> bool {
if data.is_empty() {
return false;
}
let sent = unsafe {
xStreamBufferSend(
self.handle,
data.as_ptr() as *const c_void,
data.len(),
ticks,
)
};
sent == data.len()
}
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)
}
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 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 next_message_size(&self) -> usize {
unsafe { xStreamBufferNextMessageLengthBytes(self.handle) }
}
pub fn bytes_used(&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
}
}