diff --git a/source/queue.rs b/source/queue.rs new file mode 100644 index 0000000..b61cb90 --- /dev/null +++ b/source/queue.rs @@ -0,0 +1,620 @@ +use std::collections::VecDeque; +use crate::port::*; +use crate::list::*; +use crate::queue_h::*; +use crate::*; +use crate::task_queue::*; + +pub const queueQUEUE_IS_MUTEX: UBaseType = 0; +pub const queueUNLOCKED: i8 = -1; +pub const queueLOCKED_UNMODIFIED: i8 = 0; +pub const queueSEMAPHORE_QUEUE_ITEM_LENGTH: UBaseType = 0; +pub const queueMUTEX_GIVE_BLOCK_TIME: TickType = 0; + +#[derive(Default)] +pub struct QueueDefinition + where + T: Default + Clone +{ + pcQueue: VecDeque, + + pcHead: UBaseType, + pcTail: UBaseType, + pcWriteTo: UBaseType, + + QueueUnion: UBaseType, + + xTasksWaitingToSend: ListLink, + xTasksWaitingToReceive: ListLink, + + uxMessagesWaiting: UBaseType, + uxLength: UBaseType, + cRxLock: i8, + cTxLock: i8, + + #[cfg(all( + feature = "configSUPPORT_STATIC_ALLOCATION", + feature = "configSUPPORT_DYNAMIC_ALLOCATION" + ))] + ucStaticallyAllocated: u8, + + #[cfg(feature = "configUSE_QUEUE_SETS")] + pxQueueSetContainer: Option>, + + #[cfg(feature = "configUSE_TRACE_FACILITY")] + uxQueueNumber: UBaseType, + ucQueueType: QueueType, +} +impl QueueDefinition + where + T: Default + Clone, +{ + #[cfg(feature = "configSUPPORT_DYNAMIC_ALLOCATION")] + pub fn xQueueGenericCreate(uxQueueLength: UBaseType, ucQueueType: QueueType) -> Self { + let mut queue: QueueDefinition = Default::default(); + queue.pcQueue = VecDeque::with_capacity(uxQueueLength as usize); + queue.prvInitialiseNewQueue(uxQueueLength, ucQueueType); + queue + } + pub fn prvInitialiseNewQueue(&mut self, uxQueueLength: UBaseType, ucQueueType: QueueType) { + self.pcHead = 0; + self.uxLength = uxQueueLength; + self.xQueueGenericReset(true); + + self.ucQueueType = ucQueueType; + + { + #[cfg(feature = "configUSE_QUEUE_SETS")] + self.pxQueueSetContainer = None; + } + + traceQUEUE_CREATE!(&self); + } + pub fn xQueueGenericReset(&mut self, xNewQueue: bool) -> Result<(), QueueError> { + taskENTER_CRITICAL!(); + { + self.pcTail = self.pcHead + self.uxLength; + self.uxMessagesWaiting = 0 as UBaseType; + self.pcWriteTo = self.pcHead; + self.QueueUnion = self.pcHead + self.uxLength - (1 as UBaseType); //QueueUnion represents pcReadFrom + self.cRxLock = queueUNLOCKED; + self.cTxLock = queueUNLOCKED; + self.pcQueue.clear(); + if xNewQueue == false { + if list::list_is_empty(&self.xTasksWaitingToSend) == false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToSend) != false { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + self.xTasksWaitingToSend = Default::default(); + self.xTasksWaitingToReceive = Default::default(); + } + } + taskEXIT_CRITICAL!(); + Ok(()) + } + pub fn xQueueGenericSend( + &mut self, + pvItemToQueue: T, + xTicksToWait: TickType, + xCopyPosition: BaseType, + ) -> Result<(), QueueError> { + let mut xEntryTimeSet: bool = false; + let mut xTimeOut: time_out = Default::default(); + let mut xTicksToWait = xTicksToWait; + + assert!(!((xCopyPosition == queueOVERWRITE) && self.uxLength == 1)); + + #[cfg(all(feature = "xTaskGetSchedulerState", feature = "configUSE_TIMERS"))] + assert!( + !((kernel::task_get_scheduler_state() == SchedulerState::Suspended) + && (xTicksToWait != 0)) + ); + trace!("Enter function queue_generic_send! TicksToWait: {}, uxMessageWaiting: {}, xCopyPosition: {}", xTicksToWait ,self.uxMessagesWaiting, xCopyPosition); + loop { + taskENTER_CRITICAL!(); + { + if self.uxMessagesWaiting < self.uxLength || xCopyPosition == queueOVERWRITE { + traceQUEUE_SEND!(&self); + self.prvCopyDataToQueue(pvItemToQueue, xCopyPosition); + trace!("Queue can be sent"); + #[cfg(feature = "configUSE_QUEUE_SETS")] + match self.pxQueueSetContainer { + Some => { + if notify_queue_set_container(&self, &xCopyPosition) != false { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + None => { + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::task_remove_from_event_list( + &self.xTasksWaitingToReceive, + ) { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } + } + + { + #[cfg(not(feature = "configUSE_QUEUE_SETS"))] + if !list::list_is_empty(&self.xTasksWaitingToReceive) { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToReceive) + { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + taskEXIT_CRITICAL!(); + return Ok(()); + } else { + { + #[cfg(feature = "configUSE_MUTEXES")] + if self.ucQueueType == QueueType::Mutex || self.ucQueueType == QueueType::RecursiveMutex { + taskENTER_CRITICAL!(); + { + let task_handle = self.transed_task_handle_for_mutex(); + task_queue::task_priority_inherit(task_handle); + } + taskEXIT_CRITICAL!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + if xTicksToWait == 0 as TickType { + taskEXIT_CRITICAL!(); + traceQUEUE_SEND_FAILED!(&self); + trace!("Queue Send: QueueFull"); + return Err(QueueError::QueueFull); + } else if !xEntryTimeSet { + task_queue::vTaskSetTimeOutState(&mut xTimeOut); + xEntryTimeSet = true; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } + taskEXIT_CRITICAL!(); + kernel::task_suspend_all(); + self.prvLockQueue(); + if !task_queue::xTaskCheckForTimeOut(&mut xTimeOut, &mut xTicksToWait) { + if self.prvIsQueueFull() { + traceBLOCKING_ON_QUEUE_SEND!(&self); + trace!("queue_generic_send place on event list"); + task_queue::vTaskPlaceOnEventList(&self.xTasksWaitingToSend, xTicksToWait); + self.prvUnlockQueue(); + if !kernel::task_resume_all() { + portYIELD_WITHIN_API!(); + } + } else { + self.prvUnlockQueue(); + kernel::task_resume_all(); + } + } else { + self.prvUnlockQueue(); + kernel::task_resume_all(); + + traceQUEUE_SEND_FAILED!(self); + return Err(QueueError::QueueFull); + } + } + } + pub fn xQueueGenericSendFromISR( + &mut self, + pvItemToQueue: T, + xCopyPosition: BaseType, + ) -> (Result<(), QueueError>, bool) { + let mut xReturn: Result<(), QueueError> = Ok(()); + let mut pxHigherPriorityTaskWoken: bool = false; //默认为false,下面一些情况改为true + + portASSERT_IF_INTERRUPT_PRIORITY_INVALID!(); + let uxSavedInterruptStatus: UBaseType = portSET_INTERRUPT_MASK_FROM_ISR!() as UBaseType; + { + if self.uxMessagesWaiting < self.uxLength || xCopyPosition == queueOVERWRITE { + let cTxLock: i8 = self.cTxLock; + traceQUEUE_SEND_FROM_ISR!(&self); + self.prvCopyDataToQueue(pvItemToQueue, xCopyPosition); + + if cTxLock == queueUNLOCKED { + #[cfg(feature = "configUSE_QUEUE_SETS")] + match self.pxQueueSetContainer { + Some => { + if notify_queue_set_container(self, xCopyPosition) != false { + pxHigherPriorityTaskWoken = true + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + None => { + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::task_remove_from_event_list( + &self.xTasksWaitingToReceive, + ) != false + { + pxHigherPriorityTaskWoken = true; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } + + { + #[cfg(not(feature = "configUSE_QUEUE_SETS"))] + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToReceive) + != false + { + pxHigherPriorityTaskWoken = true; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } else { + self.cTxLock = (cTxLock + 1) as i8; + } + xReturn = Ok(()); + } else { + traceQUEUE_SEND_FROM_ISR_FAILED!(&self); + xReturn = Err(QueueError::QueueFull); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR!(uxSavedInterruptStatus); + (xReturn, pxHigherPriorityTaskWoken) + } + pub fn prvLockQueue(&mut self) { + //源码中为宏,改为Queue的方法 + taskENTER_CRITICAL!(); + { + if self.cRxLock == queueUNLOCKED { + self.cRxLock = queueLOCKED_UNMODIFIED; + } + if self.cTxLock == queueUNLOCKED { + self.cTxLock = queueLOCKED_UNMODIFIED; + } + } + taskEXIT_CRITICAL!() + } + fn prvUnlockQueue(&mut self) { + taskENTER_CRITICAL!(); + { + let mut cTxLock: i8 = self.cTxLock; + while cTxLock > queueLOCKED_UNMODIFIED { + #[cfg(feature = "configUSE_QUEUE_SETS")] + match self.pxQueueSetContainer { + Some => { + if notify_queue_set_container(self, queueSEND_TO_BACK) != false { + task_queue::task_missed_yield(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + None => { + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::task_remove_from_event_list(&self.xTasksWaitingToReceive) + != false + { + task_queue::task_missed_yield(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + break; + } + } + } + { + #[cfg(not(feature = "configUSE_QUEUE_SETS"))] + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToReceive) + != false + { + task_queue::vTaskMissedYield(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + break; + } + } + + cTxLock = cTxLock - 1; + } + self.cTxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL!(); + + taskENTER_CRITICAL!(); + { + let mut cRxLock: i8 = self.cRxLock; + while cRxLock > queueLOCKED_UNMODIFIED { + if list::list_is_empty(&self.xTasksWaitingToReceive) == false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToReceive) + != false + { + task_queue::vTaskMissedYield(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + + cRxLock = cRxLock - 1; + } else { + break; + } + } + self.cRxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL!(); + } + pub fn xQueueGenericReceive( + &mut self, + mut xTicksToWait: TickType, + xJustPeeking: bool, + ) -> Result { + let mut xEntryTimeSet: bool = false; + let mut xTimeOut: time_out = Default::default(); + let mut xYieldRequired: bool = false; + let mut buffer: Option; + #[cfg(all(feature = "xTaskGetSchedulerState", feature = "configUSE_TIMERS"))] + assert!( + !((kernel::task_get_scheduler_state() == SchedulerState::Suspended) + && (xTicksToWait != 0)) + ); + loop { + trace!( + "Enter function queue_generic_receive, TicksToWait:{}, Peeking: {}!", + xTicksToWait, + xJustPeeking + ); + taskENTER_CRITICAL!(); + { + let uxMessagesWaiting: UBaseType = self.uxMessagesWaiting; + trace!( + "queue_generic_receive: uxMessageWaiting: {}", + uxMessagesWaiting + ); + if uxMessagesWaiting > 0 as UBaseType { + let pcOriginalReadPosition: UBaseType = self.QueueUnion; //QueueUnion represents pcReadFrom + buffer = self.prvCopyDataFromQueue(); // + if xJustPeeking == false { + traceQUEUE_RECEIVE!(&self); + self.uxMessagesWaiting = uxMessagesWaiting - 1; + + { + #[cfg(feature = "configUSE_MUTEXES")] + /*if uxQueueType == queueQUEUE_IS_MUTEX*/ + if self.ucQueueType == QueueType::Mutex + || self.ucQueueType == QueueType::RecursiveMutex + { + let task_handle = self.transed_task_handle_for_mutex(); + xYieldRequired = task_queue::vTaskPriorityInherit(task_handle); + self.pcQueue.pop_front(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + trace!("queue_generic_receive -- line 498"); + if list::list_is_empty(&self.xTasksWaitingToSend) == false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToSend) + != false + { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + trace!("queue_generic_receive -- line 504"); + mtCOVERAGE_TEST_MARKER!(); + } + } else if xYieldRequired == true { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + trace!("queue_generic_receive -- line 508"); + mtCOVERAGE_TEST_MARKER!(); + } + } else { + traceQUEUE_PEEK!(&self); + self.QueueUnion = pcOriginalReadPosition; + if list::list_is_empty(&self.xTasksWaitingToReceive) != false { + if task_queue::xTaskRemoveFromEventList(&self.xTasksWaitingToReceive) + != false + { + queueYIELD_IF_USING_PREEMPTION!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + taskEXIT_CRITICAL!(); + trace!("queue_generic_receive -- line 529"); + return Ok(buffer.unwrap_or_else(|| panic!("buffer is empty!"))); + } else { + if xTicksToWait == 0 as TickType { + taskEXIT_CRITICAL!(); + traceQUEUE_RECEIVE_FAILED!(&self); + return Err(QueueError::QueueEmpty); + } else if xEntryTimeSet == false { + task_queue::vTaskSetTimeOutState(&mut xTimeOut); + xEntryTimeSet = true; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } + taskEXIT_CRITICAL!(); + trace!("queue_generic_receive -- line 553"); + kernel::task_suspend_all(); + self.prvLockQueue(); + trace!("queue_generic_receive -- line 556"); + if task_queue::xTaskCheckForTimeOut(&mut xTimeOut, &mut xTicksToWait) == false { + if self.prvIsQueueEmpty() != false { + traceBLOCKING_ON_QUEUE_RECEIVE!(&self); + task_queue::task_place_on_event_list( + &self.xTasksWaitingToReceive, + xTicksToWait, + ); + self.prvUnlockQueue(); + if kernel::task_resume_all() == false { + portYIELD_WITHIN_API!(); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + self.prvUnlockQueue(); + kernel::task_resume_all(); + } + trace!("queue_generic_receive -- line 589"); + } else { + self.prvUnlockQueue(); + kernel::task_resume_all(); + if self.prvIsQueueEmpty()!= false { + traceQUEUE_RECEIVE_FAILED!(&self); + return Err(QueueError::QueueEmpty); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + } + } + pub fn prvCopyDataFromQueue(&mut self) -> Option { + self.QueueUnion += 1; + if self.QueueUnion >= self.pcTail { + self.QueueUnion = self.pcHead; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + let ret_val = self.pcQueue.get(self.QueueUnion as usize).cloned(); + Some(ret_val.unwrap()) + } + pub fn prvCopyDataToQueue(&mut self, pvItemToQueue: T, xPosition: BaseType) + { + let mut uxMessagesWaiting: UBaseType = self.uxMessagesWaiting; + { + #[cfg(feature = "configUSE_MUTEXES")] + if self.ucQueueType == QueueType::Mutex || self.ucQueueType == QueueType::RecursiveMutex + { + let mutex_holder = transed_task_handle_to_T(task_increment_mutex_held_count()); + self.pcQueue.insert(0, mutex_holder); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + + if xPosition == queueSEND_TO_BACK { + if self.ucQueueType != QueueType::Mutex && self.ucQueueType != QueueType::RecursiveMutex { + self.pcQueue.insert(self.pcWriteTo as usize, pvItemToQueue); + } else {} + self.pcWriteTo = self.pcWriteTo + 1; + + if self.pcWriteTo >= self.pcTail { + self.pcWriteTo = self.pcHead; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + if self.ucQueueType != QueueType::Mutex && self.ucQueueType != QueueType::RecursiveMutex { + self.pcQueue.insert(self.QueueUnion as usize, pvItemToQueue); + } else {} + self.QueueUnion = self.QueueUnion - 1; + if self.QueueUnion < self.pcHead { + self.QueueUnion = self.pcTail - 1; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + + if xPosition == queueOVERWRITE { + if uxMessagesWaiting > 0 as UBaseType { + uxMessagesWaiting = uxMessagesWaiting - 1; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } + self.uxMessagesWaiting = uxMessagesWaiting + 1; + } + pub fn prvIsQueueEmpty(&self) -> bool { + let mut xReturn: bool = false; + taskENTER_CRITICAL!(); + { + if self.uxMessagesWaiting == 0 as UBaseType { + xReturn = true; + } + } + taskEXIT_CRITICAL!(); + xReturn + } + pub fn prvIsQueueFull(&self) -> bool { + let mut xReturn: bool = false; + taskENTER_CRITICAL!(); + { + if self.uxMessagesWaiting == self.uxLength { + xReturn = true; + } + } + taskEXIT_CRITICAL!(); + xReturn + } + pub fn vQueueCreateCountingSemaphore(&mut self, initial_count: UBaseType) { + self.uxMessagesWaiting = initial_count; + } + pub fn vQueueUnionDecrease(&mut self) { + self.QueueUnion = self.QueueUnion - 1; + } + pub fn vQueueUnionIncrease(&mut self) { + self.QueueUnion = self.QueueUnion + 1; + } + pub fn IsQueueUnionZero(&self) -> bool { + if self.QueueUnion == 0 as UBaseType { + return true; + } else { + return false; + } + } + pub fn uxGetRecursiveCount(&self) -> UBaseType { + self.QueueUnion + } + pub fn transed_task_handle_for_mutex(&self) -> Option { + if self.pcQueue.get(0).cloned().is_some() { + let untransed_task_handle = self.pcQueue.get(0).cloned().unwrap(); + trace!("successfully get the task handle"); + let untransed_task_handle = Box::new(untransed_task_handle); + let mut task_handle: Option; + unsafe { + let transed_task_handle = std::mem::transmute::< + Box, + Box>, + >(untransed_task_handle); + task_handle = *transed_task_handle + } + task_handle + } else { + None + } + } +} +#[macro_export] +macro_rules! queueYIELD_IF_USING_PREEMPTION { + () => { + #[cfg(feature = "configUSE_PREEMPTION")] + portYIELD_WITHIN_API!(); + }; +} \ No newline at end of file diff --git a/source/queue_api.rs b/source/queue_api.rs new file mode 100644 index 0000000..5bf199a --- /dev/null +++ b/source/queue_api.rs @@ -0,0 +1,82 @@ +use crate::port::*; +use crate::queue::*; +use crate::queue_h::*; +use std::cell::UnsafeCell; + +pub struct QueueHandle_t(UnsafeCell>) + where + T: Default + Clone; +// send, sync is used for sharing queue among threads +unsafe impl Send for QueueHandle_t {} +unsafe impl Sync for QueueHandle_t {} + +impl QueueHandle_t + where + T: Default + Clone, +{ + pub fn xQueueCreate(length: UBaseType_t) -> Self { + QueueHandle_t(UnsafeCell::new(QueueDefinition::new( + length, + QueueType::Base, + ))) + } + pub fn xQueueSend(&self, pvItemToQueue: T, xTicksToWait: TickType) -> Result<(), QueueError> { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSend(pvItemToQueue, xTicksToWait, queueSEND_TO_BACK) + } + } + + pub fn xQueueSendToFront( + &self, + pvItemToQueue: T, + xTicksToWait: TickType, + ) -> Result<(), QueueError> { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSend(pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT) + } + } + pub fn xQueueSendToBack(&self, pvItemToQueue: T, xTicksToWait: TickType) -> Result<(), QueueError> { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSend(pvItemToQueue, xTicksToWait, queueSEND_TO_BACK) + } + } + pub fn xQueueOverwrite(&self, pvItemToQueue: T) -> Result<(), QueueError> { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSend(pvItemToQueue, 0, queueOVERWRITE) + } + } + pub fn xQueueSendToFrontFromISR(&self, pvItemToQueue: T) -> (Result<(), QueueError>, bool) { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSendFromISR(pvItemToQueue, queueSEND_TO_FRONT) + } + } + pub fn xQueueSendToBackFromISR(&self, pvItemToQueue: T) -> (Result<(), QueueError>, bool) { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSendFromISR(pvItemToQueue, queueSEND_TO_BACK) + } + } + pub fn xQueueOverwriteFromISR(&self, pvItemToQueue: T) -> (Result<(), QueueError>, bool) { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericSendFromISR(pvItemToQueue, queueOVERWRITE) + } + } + pub fn xQueueReceive(&self, xTicksToWait: TickType) -> Result { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericReceive(xTicksToWait, false) + } + } + pub fn xQueuePeek(&self, xTicksToWait: TickType) -> Result { + unsafe { + let inner = self.0.get(); + (*inner).xQueueGenericReceive(xTicksToWait, true) + } + } +} \ No newline at end of file diff --git a/source/queue_h.rs b/source/queue_h.rs new file mode 100644 index 0000000..8f986f1 --- /dev/null +++ b/source/queue_h.rs @@ -0,0 +1,44 @@ +use crate::port::*; +use std::fmt; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum QueueError { + QueueSendTimeout, + QueueReceiveTimeout, + MutexTimeout, + QueueFull, + QueueEmpty, +} + +impl fmt::Display for QueueError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + QueueError::QueueSendTimeout => write!(f, "QueueSendTimeOut"), + QueueError::QueueReceiveTimeout => write!(f, "QueueReceiveTimeOut"), + QueueError::MutexTimeout => write!(f, "MutexSendTimeOut"), + QueueError::QueueFull => write!(f, "QueueFull"), + QueueError::QueueEmpty => write!(f, "QueueEmpty"), + } + } +} + +pub const queueSEND_TO_BACK: BaseType = 0; +pub const queueSEND_TO_FRONT: BaseType = 1; +pub const queueOVERWRITE: BaseType = 2; + +pub const semGIVE_BLOCK_TIME: TickType = 0; + +#[derive(PartialEq)] +pub enum QueueType { + Base, + Set, + Mutex, + CountingSemaphore, + BinarySemaphore, + RecursiveMutex, +} +impl Default for QueueType { + fn default() -> Self { + QueueType::Base + } +} \ No newline at end of file diff --git a/source/semaphore.rs b/source/semaphore.rs new file mode 100644 index 0000000..4597c14 --- /dev/null +++ b/source/semaphore.rs @@ -0,0 +1,144 @@ +use crate::port::*; +use crate::queue::*; +use crate::queue_h::*; +use crate::tasks::*; +use crate::*; +use std::cell::UnsafeCell; + +pub struct Semaphore(UnsafeCell>>); +unsafe impl Send for Semaphore {} +unsafe impl Sync for Semaphore {} + +impl Semaphore { + + pub fn xSemaphoreCreateMutex() -> Self { + Semaphore(UnsafeCell::new(QueueDefinition::new(1, QueueType::Mutex))) + } + + + #[cfg(all( + feature = "configUSE_MUTEXES", + feature = "INCLUDE_xSemaphoreGetMutexHolder" + ))] + pub fn xSemaphoreGetMutexHolder(&self) -> Option { + let mut mutex_holder: Option; + taskENTER_CRITICAL!(); + { + unsafe { + let inner = self.0.get(); + mutex_holder = (*inner).queue_generic_receive(0, true).unwrap(); + } + } + taskEXIT_CRITICAL!(); + mutex_holder + } + + + pub fn xSemaphoreGive(&self) -> Result, QueueError> { + unsafe { + trace!("Semaphore up runs!"); + let inner = self.0.get(); + trace!("Semaphore up get finished!"); + (*inner).queue_generic_receive(semGIVE_BLOCK_TIME, false) + } + } + + + pub fn xSemaphoreTake(&self, xBlockTime: TickType) -> Result<(), QueueError> { + unsafe { + let inner = self.0.get(); + (*inner).queue_generic_send(None, xBlockTime, queueSEND_TO_BACK) + } + } + + + pub fn xSemaphoreCreateBinary() -> Self { + Semaphore(UnsafeCell::new(QueueDefinition::new( + 1, + QueueType::BinarySemaphore, + ))) + } + + + pub fn xSemaphoreCreateCounting (max_count: UBaseType /*,initial_count:UBaseType*/) -> Self { + let mut counting_semphr = Semaphore(UnsafeCell::new(QueueDefinition::new( + max_count, + QueueType::CountingSemaphore, + ))); + unsafe { + let inner = counting_semphr.0.get(); + (*inner).initialise_count(0); + } + //traceCREATE_COUNTING_SEMAPHORE!(); + counting_semphr + } + + + pub fn xSemaphoreCreateRecursiveMutex() -> Self { + Semaphore(UnsafeCell::new(QueueDefinition::new( + 1, + QueueType::RecursiveMutex, + ))) + } + + pub fn xSemaphoreGiveRecursive(&self) -> bool { + unsafe { + let inner = self.0.get(); + if (*inner).transed_task_handle_for_mutex().unwrap().clone() + == get_current_task_handle!() + { + traceGIVE_MUTEX_RECURSIVE!(*inner); + (*inner).QueueUnion_decrease(); + if (*inner).is_QueueUnion_zero() { + (*inner).queue_generic_receive(semGIVE_BLOCK_TIME, false); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + return true; + } else { + traceGIVE_MUTEX_RECURSIVE_FAILED!(*inner); + return false; + } + } + } + + pub fn xSemaphoreTakeRecursive(&self, ticks_to_wait: TickType) -> bool { + let mut xReturn: bool = false; + unsafe { + let inner = self.0.get(); + traceTAKE_MUTEX_RECURSIVE!(*inner); + trace!("Ready to get recursive mutex holder"); + let mutex_holder = (*inner).transed_task_handle_for_mutex(); + trace!("Get recursive mutex holder successfully"); + if mutex_holder.is_some() + { + if mutex_holder.unwrap().clone() == get_current_task_handle!() { + trace!("Not First Time get this mutex"); + (*inner).QueueUnion_increase(); + xReturn = false; + } + } + else { + trace!("First Time get this mutex"); + match (*inner).queue_generic_send(None, ticks_to_wait, queueSEND_TO_BACK) { + Ok(x) => { + (*inner).QueueUnion_increase(); + xReturn = true; + } + Err(x) => { + traceTAKE_MUTEX_RECURSIVE_FAILED!(*inner); + xReturn = false; + } + } + } + } + return xReturn; + } + + pub fn uxSemaphoreGetCount (&self) -> UBaseType { + unsafe { + let inner = self.0.get(); + (*inner).get_recursive_count() + } + } +} diff --git a/source/task_queue.rs b/source/task_queue.rs new file mode 100644 index 0000000..a8a5d2f --- /dev/null +++ b/source/task_queue.rs @@ -0,0 +1,215 @@ +use crate::list; +use crate::list::ListLink; +use crate::port::*; +use crate::kernel::*; +use crate::projdefs::pdFALSE; +use crate::tasks::*; +use crate::global::*; +use crate::*; + +#[cfg(not(feature = "configUSE_16_BIT_TICKS"))] +pub const taskEVENT_LIST_ITEM_VALUE_IN_USE: TickType_t = 0x80000000; + +pub fn xTaskRemoveFromEventList(event_list: &ListLink) -> bool { + let unblocked_tcb = list::get_owner_of_head_entry(event_list); + let mut xreturn: bool = false; + + list::uxListRemove(unblocked_tcb.get_event_list_item()); + + if GetSchedulerSuspended!() == pdFALSE as UBaseType { + list::uxListRemove(unblocked_tcb.GetStateListItem()); + unblocked_tcb.AddTasktoReadyList().Unwrap(); + } else { + list::vListInsertEnd(&PENDING_READY_LIST, unblocked_tcb.GetEventListItem()); + } + + if unblocked_tcb.GetPriority() > GetCurrentTaskPriority!() { + xreturn = true; + SetYieldPending!(true); + } else { + xreturn = false; + } + + { + #[cfg(feature = "configUSE_TICKLESS_IDLE")] + ResetNextTaskUnblockTime(); + } + + trace!("xreturn is {}", xreturn); + xreturn +} + +pub fn vTaskMissedYield() { + SetYieldPending!(false); +} + +#[derive(Debug, Default)] +pub struct time_out { + overflow_count: BaseType_t, + time_on_entering: TickType_t, +} + +pub fn vTaskSetTimeOutState(pxtimeout: &mut time_out) +{ + pxtimeout.overflow_count = GetNumOfOverFlows!(); + pxtimeout.time_on_entering = GetTickCount!(); +} + +pub fn xTaskCheckForTimeOut(pxtimeout: &mut time_out, ticks_to_wait: &mut TickType_t) -> bool { + trace!("time_out is {:?}", pxtimeout); + trace!("ticks_to_wait is {}", ticks_to_wait); + let mut xreturn: bool = false; + taskENTER_CRITICAL!(); + { + let const_tick_count: TickType_t = GetTickCount!(); + trace!("Tick_count is {}", const_tick_count); + let unwrapped_cur = GetCurrentTaskHandle!(); + let mut cfglock1 = false; + let mut cfglock2 = false; + + { + #[cfg(feature = "INCLUDE_xTaskAbortDelay")] + cfglock1 = true; + } + + { + #[cfg(feature = "INCLUDE_vTaskSuspend")] + cfglock2 = true; + } + + if cfglock1 && unwrapped_cur.GetDelayAborted() { + unwrapped_cur.SetDelayAborted(false); + xreturn = true; + } + + if cfglock2 && *ticks_to_wait == portMAX_DELAY { + xreturn = false; + } + + if GetNumOfOverflows!() != pxtimeout.overflow_count + && const_tick_count >= pxtimeout.time_on_entering + { + trace!("IF"); + xreturn = true; + } else if const_tick_count - pxtimeout.time_on_entering < *ticks_to_wait { + trace!("ELSE IF"); + *ticks_to_wait -= const_tick_count - pxtimeout.time_on_entering; + vTaskSetTimeOutState(pxtimeout); + xreturn = false; + } else { + trace!("ELSE"); + xreturn = true; + } + } + taskEXIT_CRITICAL!(); + xreturn +} + +pub fn vTaskPlaceOnEventList(event_list: &ListLink, ticks_to_wait: TickType_t) { + let unwrapped_cur = GetCurrentTaskHandle!(); + trace!("INSERT"); + list::vListInsert(event_list, unwrapped_cur.GetEventListItem()); + trace!("INSERT SUCCEEDED"); + AddCurrentTaskToDelayedList(ticks_to_wait, true); + trace!("ADD SUCCEEDED"); +} + + +#[cfg(feature = "configUSE_MUTEXES")] +pub fn pvTaskIncrementMutexHeldCount() -> Option { + match GetCurrentTaskHandleWrapped!() { + Some(current_task) => { + let new_val = current_task.GetMutexHeldCount() + 1; + current_task.SetMutexHeldCount(new_val); + Some(current_task.clone()) + } + None => None, + } +} + +#[cfg(feature = "configUSE_MUTEXES")] +pub fn vTaskPriorityInherit(mutex_holder: Option) +{ + trace!("Enter function 'TaskPriorityInherit'"); + if mutex_holder.IsSome() { + trace!("Mutex holder exists!"); + let task = mutex_holder.Unwrap(); + let current_task_priority = GetCurrentTaskPriority!(); + let this_task_priority = task.GetPriority(); + + if this_task_priority < current_task_priority { + trace!("change priority!"); + let event_list_item = task.GetEventListItem(); + if (list::listGET_LIST_ITEM_VALUE(&event_list_item) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0 + { + let new_item_val = (configMAX_PRIORITIES!() - current_task_priority) as TickType_t; + list::listSET_LIST_ITEM_VALUE(&event_list_item, new_item_val); + } else { + mtCOVERAGE_TEST_MARKER!() + } + let state_list_item = task.GetStateListItem(); + if list::is_contained_within( + &READY_TASK_LISTS[this_task_priority as usize], + &state_list_item, + ) { + if list::uxListRemove(state_list_item) == 0 { + taskRESET_READY_PRIORITY!(this_task_priority); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + task.SetPriority(current_task_priority); + task.AddTaskToReadyList().Unwrap(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } +} + +#[cfg(feature = "configUSE_MUTEXES")] +pub fn xTaskPriorityDisinherit(mutex_holder: Option) -> bool { + let mut ret_val: bool = false; + trace!("Enter function 'xTaskPriorityDisinherit'"); + if let Some(task) = mutex_holder { + + assert!(task == get_current_task_handle!()); + + let mutex_held = task.GetMutexHeldCount(); + assert!(mutex_held > 0); + let mutex_held = mutex_held - 1; + task.SetMutexHeldCount(mutex_held); + + let this_task_priority = task.GetPriority(); + let this_task_base_priority = task.GetBasePriority(); + if this_task_priority != this_task_base_priority { + + if mutex_held == 0 { + let state_list_item = task.GetStateListItem(); + if list::uxListRemove(state_list_item) == 0 { + taskRESET_READY_PRIORITY!(this_task_priority); + } else { + mtCOVERAGE_TEST_MARKER!(); + } + traceTASK_PRIORITY_DISINHERIT!(&task, this_task_base_priority); + task.SetPriority(this_task_base_priority); + + let new_item_val = (configMAX_PRIORITIES!() - this_task_priority) as TickType_t; + list::listSET_LIST_ITEM_VALUE(&task.get_event_list_item(), new_item_val); + task.AddTaskToReadyList().Unwrap(); + + ret_val = true; + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + } else { + mtCOVERAGE_TEST_MARKER!(); + } + + ret_val +} +