use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use crate::kernel::queue::{
queueQUEUE_TYPE_MUTEX, xQueueCreateMutexStatic, xQueueGenericSend, xQueueSemaphoreTake,
QueueHandle_t, StaticQueue_t, queueSEND_TO_BACK,
};
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
use crate::kernel::queue::xQueueCreateMutex;
use crate::types::*;
pub struct Mutex<T> {
handle: QueueHandle_t,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {}
impl<T> Mutex<T> {
#[cfg(any(feature = "alloc", feature = "heap-4", feature = "heap-5"))]
pub fn new(value: T) -> Option<Self> {
let handle = unsafe { xQueueCreateMutex(queueQUEUE_TYPE_MUTEX) };
if handle.is_null() {
None
} else {
Some(Self {
handle,
data: UnsafeCell::new(value),
})
}
}
pub fn new_static(value: T, mutex_buffer: &'static mut StaticQueue_t) -> Option<Self> {
let handle =
unsafe { xQueueCreateMutexStatic(queueQUEUE_TYPE_MUTEX, mutex_buffer as *mut StaticQueue_t) };
if handle.is_null() {
None
} else {
Some(Self {
handle,
data: UnsafeCell::new(value),
})
}
}
pub fn lock(&self) -> MutexGuard<'_, T> {
unsafe {
let result = xQueueSemaphoreTake(self.handle, portMAX_DELAY);
debug_assert_eq!(result, pdTRUE, "Mutex take with infinite timeout failed");
}
MutexGuard { mutex: self, _not_send: core::marker::PhantomData }
}
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
let result = unsafe { xQueueSemaphoreTake(self.handle, 0) };
if result == pdTRUE {
Some(MutexGuard { mutex: self, _not_send: core::marker::PhantomData })
} else {
None
}
}
pub fn lock_timeout(&self, ticks: TickType_t) -> Option<MutexGuard<'_, T>> {
let result = unsafe { xQueueSemaphoreTake(self.handle, ticks) };
if result == pdTRUE {
Some(MutexGuard { mutex: self, _not_send: core::marker::PhantomData })
} else {
None
}
}
pub unsafe fn raw_handle(&self) -> QueueHandle_t {
self.handle
}
fn release(&self) {
unsafe {
xQueueGenericSend(self.handle, core::ptr::null(), 0, queueSEND_TO_BACK);
}
}
}
pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
_not_send: core::marker::PhantomData<*const ()>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.data.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.mutex.release();
}
}