949 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			949 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2013-2019 Arm Limited. All rights reserved.
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the License); you may
 | |
|  * not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  * www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | |
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  *
 | |
|  * -----------------------------------------------------------------------------
 | |
|  *
 | |
|  * Project:     CMSIS-RTOS RTX
 | |
|  * Title:       Message Queue functions
 | |
|  *
 | |
|  * -----------------------------------------------------------------------------
 | |
|  */
 | |
| 
 | |
| #include "rtx_lib.h"
 | |
| 
 | |
| 
 | |
| //  OS Runtime Object Memory Usage
 | |
| #if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
 | |
| osRtxObjectMemUsage_t osRtxMessageQueueMemUsage \
 | |
| __attribute__((section(".data.os.msgqueue.obj"))) =
 | |
| { 0U, 0U, 0U };
 | |
| #endif
 | |
| 
 | |
| 
 | |
| //  ==== Helper functions ====
 | |
| 
 | |
| /// Put a Message into Queue sorted by Priority (Highest at Head).
 | |
| /// \param[in]  mq              message queue object.
 | |
| /// \param[in]  msg             message object.
 | |
| static void MessageQueuePut (os_message_queue_t *mq, os_message_t *msg) {
 | |
| #if (EXCLUSIVE_ACCESS == 0)
 | |
|   uint32_t      primask = __get_PRIMASK();
 | |
| #endif
 | |
|   os_message_t *prev, *next;
 | |
| 
 | |
|   if (mq->msg_last != NULL) {
 | |
|     prev = mq->msg_last;
 | |
|     next = NULL;
 | |
|     while ((prev != NULL) && (prev->priority < msg->priority)) {
 | |
|       next = prev;
 | |
|       prev = prev->prev;
 | |
|     }
 | |
|     msg->prev = prev;
 | |
|     msg->next = next;
 | |
|     if (prev != NULL) {
 | |
|       prev->next = msg;
 | |
|     } else {
 | |
|       mq->msg_first = msg;
 | |
|     }
 | |
|     if (next != NULL) {
 | |
|       next->prev = msg;
 | |
|     } else {
 | |
|       mq->msg_last = msg;
 | |
|     }
 | |
|   } else {
 | |
|     msg->prev = NULL;
 | |
|     msg->next = NULL;
 | |
|     mq->msg_first= msg;
 | |
|     mq->msg_last = msg;
 | |
|   }
 | |
| 
 | |
| #if (EXCLUSIVE_ACCESS == 0)
 | |
|   __disable_irq();
 | |
| 
 | |
|   mq->msg_count++;
 | |
| 
 | |
|   if (primask == 0U) {
 | |
|     __enable_irq();
 | |
|   }
 | |
| #else
 | |
|   (void)atomic_inc32(&mq->msg_count);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /// Get a Message from Queue with Highest Priority.
 | |
| /// \param[in]  mq              message queue object.
 | |
| /// \return message object or NULL.
 | |
| static os_message_t *MessageQueueGet (os_message_queue_t *mq) {
 | |
| #if (EXCLUSIVE_ACCESS == 0)
 | |
|   uint32_t      primask = __get_PRIMASK();
 | |
| #endif
 | |
|   os_message_t *msg;
 | |
|   uint32_t      count;
 | |
|   uint8_t       flags;
 | |
| 
 | |
| #if (EXCLUSIVE_ACCESS == 0)
 | |
|   __disable_irq();
 | |
| 
 | |
|   count = mq->msg_count;
 | |
|   if (count != 0U) {
 | |
|     mq->msg_count--;
 | |
|   }
 | |
| 
 | |
|   if (primask == 0U) {
 | |
|     __enable_irq();
 | |
|   }
 | |
| #else
 | |
|   count = atomic_dec32_nz(&mq->msg_count);
 | |
| #endif
 | |
| 
 | |
|   if (count != 0U) {
 | |
|     msg = mq->msg_first;
 | |
| 
 | |
|     while (msg != NULL) {
 | |
| #if (EXCLUSIVE_ACCESS == 0)
 | |
|       __disable_irq();
 | |
| 
 | |
|       flags = msg->flags;
 | |
|       msg->flags = 1U;
 | |
| 
 | |
|       if (primask == 0U) {
 | |
|         __enable_irq();
 | |
|       }
 | |
| #else
 | |
|       flags = atomic_wr8(&msg->flags, 1U);
 | |
| #endif
 | |
|       if (flags == 0U) {
 | |
|         break;
 | |
|       }
 | |
|       msg = msg->next;
 | |
|     }
 | |
|   } else {
 | |
|     msg = NULL;
 | |
|   }
 | |
| 
 | |
|   return msg;
 | |
| }
 | |
| 
 | |
| /// Remove a Message from Queue
 | |
| /// \param[in]  mq              message queue object.
 | |
| /// \param[in]  msg             message object.
 | |
| static void MessageQueueRemove (os_message_queue_t *mq, const os_message_t *msg) {
 | |
| 
 | |
|   if (msg->prev != NULL) {
 | |
|     msg->prev->next = msg->next;
 | |
|   } else {
 | |
|     mq->msg_first = msg->next;
 | |
|   }
 | |
|   if (msg->next != NULL) {
 | |
|     msg->next->prev = msg->prev;
 | |
|   } else {
 | |
|     mq->msg_last = msg->prev;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| //  ==== Post ISR processing ====
 | |
| 
 | |
| /// Message Queue post ISR processing.
 | |
| /// \param[in]  msg             message object.
 | |
| static void osRtxMessageQueuePostProcess (os_message_t *msg) {
 | |
|   os_message_queue_t *mq;
 | |
|   os_message_t       *msg0;
 | |
|   os_thread_t        *thread;
 | |
|   const uint32_t     *reg;
 | |
|   const void         *ptr_src;
 | |
|         void         *ptr_dst;
 | |
| 
 | |
|   if (msg->flags != 0U) {
 | |
|     // Remove Message
 | |
|     //lint -e{9079} -e{9087} "cast between pointers to different object types"
 | |
|     mq = *((os_message_queue_t **)(void *)&msg[1]);
 | |
|     MessageQueueRemove(mq, msg);
 | |
|     // Free memory
 | |
|     msg->id = osRtxIdInvalid;
 | |
|     (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
 | |
|     // Check if Thread is waiting to send a Message
 | |
|     if (mq->thread_list != NULL) {
 | |
|       // Try to allocate memory
 | |
|       //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|       msg0 = osRtxMemoryPoolAlloc(&mq->mp_info);
 | |
|       if (msg0 != NULL) {
 | |
|         // Wakeup waiting Thread with highest Priority
 | |
|         thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|         osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
 | |
|         // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
 | |
|         reg = osRtxThreadRegPtr(thread);
 | |
|         //lint -e{923} "cast from unsigned int to pointer"
 | |
|         ptr_src = (const void *)reg[2];
 | |
|         memcpy(&msg0[1], ptr_src, mq->msg_size);
 | |
|         // Store Message into Queue
 | |
|         msg0->id       = osRtxIdMessage;
 | |
|         msg0->flags    = 0U;
 | |
|         msg0->priority = (uint8_t)reg[3];
 | |
|         MessageQueuePut(mq, msg0);
 | |
|         EvrRtxMessageQueueInserted(mq, ptr_src);
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     // New Message
 | |
|     //lint -e{9079} -e{9087} "cast between pointers to different object types"
 | |
|     mq = (void *)msg->next;
 | |
|     //lint -e{9087} "cast between pointers to different object types"
 | |
|     ptr_src = (const void *)msg->prev;
 | |
|     // Check if Thread is waiting to receive a Message
 | |
|     if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
 | |
|       EvrRtxMessageQueueInserted(mq, ptr_src);
 | |
|       // Wakeup waiting Thread with highest Priority
 | |
|       thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|       osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
 | |
|       // Copy Message (R2: void *msg_ptr, R3: uint8_t *msg_prio)
 | |
|       reg = osRtxThreadRegPtr(thread);
 | |
|       //lint -e{923} "cast from unsigned int to pointer"
 | |
|       ptr_dst = (void *)reg[2];
 | |
|       memcpy(ptr_dst, &msg[1], mq->msg_size);
 | |
|       if (reg[3] != 0U) {
 | |
|         //lint -e{923} -e{9078} "cast from unsigned int to pointer"
 | |
|         *((uint8_t *)reg[3]) = msg->priority;
 | |
|       }
 | |
|       EvrRtxMessageQueueRetrieved(mq, ptr_dst);
 | |
|       // Free memory
 | |
|       msg->id = osRtxIdInvalid;
 | |
|       (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
 | |
|     } else {
 | |
|       EvrRtxMessageQueueInserted(mq, ptr_src);
 | |
|       MessageQueuePut(mq, msg);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| //  ==== Service Calls ====
 | |
| 
 | |
| /// Create and Initialize a Message Queue object.
 | |
| /// \note API identical to osMessageQueueNew
 | |
| static osMessageQueueId_t svcRtxMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
 | |
|   os_message_queue_t *mq;
 | |
|   void               *mq_mem;
 | |
|   uint32_t            mq_size;
 | |
|   uint32_t            block_size;
 | |
|   uint32_t            size;
 | |
|   uint8_t             flags;
 | |
|   const char         *name;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((msg_count == 0U) || (msg_size  == 0U)) {
 | |
|     EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return NULL;
 | |
|   }
 | |
|   block_size = ((msg_size + 3U) & ~3UL) + sizeof(os_message_t);
 | |
|   if ((__CLZ(msg_count) + __CLZ(block_size)) < 32U) {
 | |
|     EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   size = msg_count * block_size;
 | |
| 
 | |
|   // Process attributes
 | |
|   if (attr != NULL) {
 | |
|     name    = attr->name;
 | |
|     //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
 | |
|     mq      = attr->cb_mem;
 | |
|     //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
 | |
|     mq_mem  = attr->mq_mem;
 | |
|     mq_size = attr->mq_size;
 | |
|     if (mq != NULL) {
 | |
|       //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
 | |
|       if ((((uint32_t)mq & 3U) != 0U) || (attr->cb_size < sizeof(os_message_queue_t))) {
 | |
|         EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
 | |
|         //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|         return NULL;
 | |
|       }
 | |
|     } else {
 | |
|       if (attr->cb_size != 0U) {
 | |
|         EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
 | |
|         //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|         return NULL;
 | |
|       }
 | |
|     }
 | |
|     if (mq_mem != NULL) {
 | |
|       //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
 | |
|       if ((((uint32_t)mq_mem & 3U) != 0U) || (mq_size < size)) {
 | |
|         EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
 | |
|         //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|         return NULL;
 | |
|       }
 | |
|     } else {
 | |
|       if (mq_size != 0U) {
 | |
|         EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
 | |
|         //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|         return NULL;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     name   = NULL;
 | |
|     mq     = NULL;
 | |
|     mq_mem = NULL;
 | |
|   }
 | |
| 
 | |
|   // Allocate object memory if not provided
 | |
|   if (mq == NULL) {
 | |
|     if (osRtxInfo.mpi.message_queue != NULL) {
 | |
|       //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|       mq = osRtxMemoryPoolAlloc(osRtxInfo.mpi.message_queue);
 | |
|     } else {
 | |
|       //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|       mq = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_message_queue_t), 1U);
 | |
|     }
 | |
| #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
 | |
|     if (mq != NULL) {
 | |
|       uint32_t used;
 | |
|       osRtxMessageQueueMemUsage.cnt_alloc++;
 | |
|       used = osRtxMessageQueueMemUsage.cnt_alloc - osRtxMessageQueueMemUsage.cnt_free;
 | |
|       if (osRtxMessageQueueMemUsage.max_used < used) {
 | |
|         osRtxMessageQueueMemUsage.max_used = used;
 | |
|       }
 | |
|     }
 | |
| #endif
 | |
|     flags = osRtxFlagSystemObject;
 | |
|   } else {
 | |
|     flags = 0U;
 | |
|   }
 | |
| 
 | |
|   // Allocate data memory if not provided
 | |
|   if ((mq != NULL) && (mq_mem == NULL)) {
 | |
|     //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|     mq_mem = osRtxMemoryAlloc(osRtxInfo.mem.mq_data, size, 0U);
 | |
|     if (mq_mem == NULL) {
 | |
|       if ((flags & osRtxFlagSystemObject) != 0U) {
 | |
|         if (osRtxInfo.mpi.message_queue != NULL) {
 | |
|           (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
 | |
|         } else {
 | |
|           (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
 | |
|         }
 | |
| #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
 | |
|         osRtxMessageQueueMemUsage.cnt_free++;
 | |
| #endif
 | |
|       }
 | |
|       mq = NULL;
 | |
|     } else {
 | |
|       memset(mq_mem, 0, size);
 | |
|     }
 | |
|     flags |= osRtxFlagSystemMemory;
 | |
|   }
 | |
| 
 | |
|   if (mq != NULL) {
 | |
|     // Initialize control block
 | |
|     mq->id          = osRtxIdMessageQueue;
 | |
|     mq->flags       = flags;
 | |
|     mq->name        = name;
 | |
|     mq->thread_list = NULL;
 | |
|     mq->msg_size    = msg_size;
 | |
|     mq->msg_count   = 0U;
 | |
|     mq->msg_first   = NULL;
 | |
|     mq->msg_last    = NULL;
 | |
|     (void)osRtxMemoryPoolInit(&mq->mp_info, msg_count, block_size, mq_mem);
 | |
| 
 | |
|     // Register post ISR processing function
 | |
|     osRtxInfo.post_process.message = osRtxMessageQueuePostProcess;
 | |
| 
 | |
|     EvrRtxMessageQueueCreated(mq, mq->name);
 | |
|   } else {
 | |
|     EvrRtxMessageQueueError(NULL, (int32_t)osErrorNoMemory);
 | |
|   }
 | |
| 
 | |
|   return mq;
 | |
| }
 | |
| 
 | |
| /// Get name of a Message Queue object.
 | |
| /// \note API identical to osMessageQueueGetName
 | |
| static const char *svcRtxMessageQueueGetName (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueGetName(mq, NULL);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueGetName(mq, mq->name);
 | |
| 
 | |
|   return mq->name;
 | |
| }
 | |
| 
 | |
| /// Put a Message into a Queue or timeout if Queue is full.
 | |
| /// \note API identical to osMessageQueuePut
 | |
| static osStatus_t svcRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_message_t       *msg;
 | |
|   os_thread_t        *thread;
 | |
|   uint32_t           *reg;
 | |
|   void               *ptr;
 | |
|   osStatus_t          status;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Check if Thread is waiting to receive a Message
 | |
|   if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
 | |
|     EvrRtxMessageQueueInserted(mq, msg_ptr);
 | |
|     // Wakeup waiting Thread with highest Priority
 | |
|     thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|     osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
 | |
|     // Copy Message (R2: void *msg_ptr, R3: uint8_t *msg_prio)
 | |
|     reg = osRtxThreadRegPtr(thread);
 | |
|     //lint -e{923} "cast from unsigned int to pointer"
 | |
|     ptr = (void *)reg[2];
 | |
|     memcpy(ptr, msg_ptr, mq->msg_size);
 | |
|     if (reg[3] != 0U) {
 | |
|       //lint -e{923} -e{9078} "cast from unsigned int to pointer"
 | |
|       *((uint8_t *)reg[3]) = msg_prio;
 | |
|     }
 | |
|     EvrRtxMessageQueueRetrieved(mq, ptr);
 | |
|     status = osOK;
 | |
|   } else {
 | |
|     // Try to allocate memory
 | |
|     //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|     msg = osRtxMemoryPoolAlloc(&mq->mp_info);
 | |
|     if (msg != NULL) {
 | |
|       // Copy Message
 | |
|       memcpy(&msg[1], msg_ptr, mq->msg_size);
 | |
|       // Put Message into Queue
 | |
|       msg->id       = osRtxIdMessage;
 | |
|       msg->flags    = 0U;
 | |
|       msg->priority = msg_prio;
 | |
|       MessageQueuePut(mq, msg);
 | |
|       EvrRtxMessageQueueInserted(mq, msg_ptr);
 | |
|       status = osOK;
 | |
|     } else {
 | |
|       // No memory available
 | |
|       if (timeout != 0U) {
 | |
|         EvrRtxMessageQueuePutPending(mq, msg_ptr, timeout);
 | |
|         // Suspend current Thread
 | |
|         if (osRtxThreadWaitEnter(osRtxThreadWaitingMessagePut, timeout)) {
 | |
|           osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
 | |
|           // Save arguments (R2: const void *msg_ptr, R3: uint8_t msg_prio)
 | |
|           //lint -e{923} -e{9078} "cast from unsigned int to pointer"
 | |
|           reg = (uint32_t *)(__get_PSP());
 | |
|           //lint -e{923} -e{9078} "cast from pointer to unsigned int"
 | |
|           reg[2] = (uint32_t)msg_ptr;
 | |
|           //lint -e{923} -e{9078} "cast from pointer to unsigned int"
 | |
|           reg[3] = (uint32_t)msg_prio;
 | |
|         } else {
 | |
|           EvrRtxMessageQueuePutTimeout(mq);
 | |
|         }
 | |
|         status = osErrorTimeout;
 | |
|       } else {
 | |
|         EvrRtxMessageQueueNotInserted(mq, msg_ptr);
 | |
|         status = osErrorResource;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Get a Message from a Queue or timeout if Queue is empty.
 | |
| /// \note API identical to osMessageQueueGet
 | |
| static osStatus_t svcRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_message_t       *msg;
 | |
|   os_thread_t        *thread;
 | |
|   uint32_t           *reg;
 | |
|   const void         *ptr;
 | |
|   osStatus_t          status;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Get Message from Queue
 | |
|   msg = MessageQueueGet(mq);
 | |
|   if (msg != NULL) {
 | |
|     MessageQueueRemove(mq, msg);
 | |
|     // Copy Message
 | |
|     memcpy(msg_ptr, &msg[1], mq->msg_size);
 | |
|     if (msg_prio != NULL) {
 | |
|       *msg_prio = msg->priority;
 | |
|     }
 | |
|     EvrRtxMessageQueueRetrieved(mq, msg_ptr);
 | |
|     // Free memory
 | |
|     msg->id = osRtxIdInvalid;
 | |
|     (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
 | |
|     // Check if Thread is waiting to send a Message
 | |
|     if (mq->thread_list != NULL) {
 | |
|       // Try to allocate memory
 | |
|       //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|       msg = osRtxMemoryPoolAlloc(&mq->mp_info);
 | |
|       if (msg != NULL) {
 | |
|         // Wakeup waiting Thread with highest Priority
 | |
|         thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|         osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
 | |
|         // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
 | |
|         reg = osRtxThreadRegPtr(thread);
 | |
|         //lint -e{923} "cast from unsigned int to pointer"
 | |
|         ptr = (const void *)reg[2];
 | |
|         memcpy(&msg[1], ptr, mq->msg_size);
 | |
|         // Store Message into Queue
 | |
|         msg->id       = osRtxIdMessage;
 | |
|         msg->flags    = 0U;
 | |
|         msg->priority = (uint8_t)reg[3];
 | |
|         MessageQueuePut(mq, msg);
 | |
|         EvrRtxMessageQueueInserted(mq, ptr);
 | |
|       }
 | |
|     }
 | |
|     status = osOK;
 | |
|   } else {
 | |
|     // No Message available
 | |
|     if (timeout != 0U) {
 | |
|       EvrRtxMessageQueueGetPending(mq, msg_ptr, timeout);
 | |
|       // Suspend current Thread
 | |
|       if (osRtxThreadWaitEnter(osRtxThreadWaitingMessageGet, timeout)) {
 | |
|         osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
 | |
|         // Save arguments (R2: void *msg_ptr, R3: uint8_t *msg_prio)
 | |
|         //lint -e{923} -e{9078} "cast from unsigned int to pointer"
 | |
|         reg = (uint32_t *)(__get_PSP());
 | |
|         //lint -e{923} -e{9078} "cast from pointer to unsigned int"
 | |
|         reg[2] = (uint32_t)msg_ptr;
 | |
|         //lint -e{923} -e{9078} "cast from pointer to unsigned int"
 | |
|         reg[3] = (uint32_t)msg_prio;
 | |
|       } else {
 | |
|         EvrRtxMessageQueueGetTimeout(mq);
 | |
|       }
 | |
|       status = osErrorTimeout;
 | |
|     } else {
 | |
|       EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
 | |
|       status = osErrorResource;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Get maximum number of messages in a Message Queue.
 | |
| /// \note API identical to osMessageQueueGetCapacity
 | |
| static uint32_t svcRtxMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueGetCapacity(mq, 0U);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return 0U;
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueGetCapacity(mq, mq->mp_info.max_blocks);
 | |
| 
 | |
|   return mq->mp_info.max_blocks;
 | |
| }
 | |
| 
 | |
| /// Get maximum message size in a Memory Pool.
 | |
| /// \note API identical to osMessageQueueGetMsgSize
 | |
| static uint32_t svcRtxMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueGetMsgSize(mq, 0U);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return 0U;
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueGetMsgSize(mq, mq->msg_size);
 | |
| 
 | |
|   return mq->msg_size;
 | |
| }
 | |
| 
 | |
| /// Get number of queued messages in a Message Queue.
 | |
| /// \note API identical to osMessageQueueGetCount
 | |
| static uint32_t svcRtxMessageQueueGetCount (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueGetCount(mq, 0U);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return 0U;
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueGetCount(mq, mq->msg_count);
 | |
| 
 | |
|   return mq->msg_count;
 | |
| }
 | |
| 
 | |
| /// Get number of available slots for messages in a Message Queue.
 | |
| /// \note API identical to osMessageQueueGetSpace
 | |
| static uint32_t svcRtxMessageQueueGetSpace (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueGetSpace(mq, 0U);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return 0U;
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueGetSpace(mq, mq->mp_info.max_blocks - mq->msg_count);
 | |
| 
 | |
|   return (mq->mp_info.max_blocks - mq->msg_count);
 | |
| }
 | |
| 
 | |
| /// Reset a Message Queue to initial empty state.
 | |
| /// \note API identical to osMessageQueueReset
 | |
| static osStatus_t svcRtxMessageQueueReset (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_message_t       *msg;
 | |
|   os_thread_t        *thread;
 | |
|   const uint32_t     *reg;
 | |
|   const void         *ptr;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Remove Messages from Queue
 | |
|   for (;;) {
 | |
|     // Get Message from Queue
 | |
|     msg = MessageQueueGet(mq);
 | |
|     if (msg == NULL) {
 | |
|       break;
 | |
|     }
 | |
|     MessageQueueRemove(mq, msg);
 | |
|     EvrRtxMessageQueueRetrieved(mq, NULL);
 | |
|     // Free memory
 | |
|     msg->id = osRtxIdInvalid;
 | |
|     (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
 | |
|   }
 | |
| 
 | |
|   // Check if Threads are waiting to send Messages
 | |
|   if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessagePut)) {
 | |
|     do {
 | |
|       // Try to allocate memory
 | |
|       //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|       msg = osRtxMemoryPoolAlloc(&mq->mp_info);
 | |
|       if (msg != NULL) {
 | |
|         // Wakeup waiting Thread with highest Priority
 | |
|         thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|         osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
 | |
|         // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
 | |
|         reg = osRtxThreadRegPtr(thread);
 | |
|         //lint -e{923} "cast from unsigned int to pointer"
 | |
|         ptr = (const void *)reg[2];
 | |
|         memcpy(&msg[1], ptr, mq->msg_size);
 | |
|         // Store Message into Queue
 | |
|         msg->id       = osRtxIdMessage;
 | |
|         msg->flags    = 0U;
 | |
|         msg->priority = (uint8_t)reg[3];
 | |
|         MessageQueuePut(mq, msg);
 | |
|         EvrRtxMessageQueueInserted(mq, ptr);
 | |
|       }
 | |
|     } while ((msg != NULL) && (mq->thread_list != NULL));
 | |
|     osRtxThreadDispatch(NULL);
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueResetDone(mq);
 | |
| 
 | |
|   return osOK;
 | |
| }
 | |
| 
 | |
| /// Delete a Message Queue object.
 | |
| /// \note API identical to osMessageQueueDelete
 | |
| static osStatus_t svcRtxMessageQueueDelete (osMessageQueueId_t mq_id) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_thread_t        *thread;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Unblock waiting threads
 | |
|   if (mq->thread_list != NULL) {
 | |
|     do {
 | |
|       thread = osRtxThreadListGet(osRtxObject(mq));
 | |
|       osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
 | |
|     } while (mq->thread_list != NULL);
 | |
|     osRtxThreadDispatch(NULL);
 | |
|   }
 | |
| 
 | |
|   // Mark object as invalid
 | |
|   mq->id = osRtxIdInvalid;
 | |
| 
 | |
|   // Free data memory
 | |
|   if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
 | |
|     (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
 | |
|   }
 | |
| 
 | |
|   // Free object memory
 | |
|   if ((mq->flags & osRtxFlagSystemObject) != 0U) {
 | |
|     if (osRtxInfo.mpi.message_queue != NULL) {
 | |
|       (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
 | |
|     } else {
 | |
|       (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
 | |
|     }
 | |
| #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
 | |
|     osRtxMessageQueueMemUsage.cnt_free++;
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   EvrRtxMessageQueueDestroyed(mq);
 | |
| 
 | |
|   return osOK;
 | |
| }
 | |
| 
 | |
| //  Service Calls definitions
 | |
| //lint ++flb "Library Begin" [MISRA Note 11]
 | |
| SVC0_3(MessageQueueNew,         osMessageQueueId_t, uint32_t, uint32_t, const osMessageQueueAttr_t *)
 | |
| SVC0_1(MessageQueueGetName,     const char *,       osMessageQueueId_t)
 | |
| SVC0_4(MessageQueuePut,         osStatus_t,         osMessageQueueId_t, const void *, uint8_t,   uint32_t)
 | |
| SVC0_4(MessageQueueGet,         osStatus_t,         osMessageQueueId_t,       void *, uint8_t *, uint32_t)
 | |
| SVC0_1(MessageQueueGetCapacity, uint32_t,           osMessageQueueId_t)
 | |
| SVC0_1(MessageQueueGetMsgSize,  uint32_t,           osMessageQueueId_t)
 | |
| SVC0_1(MessageQueueGetCount,    uint32_t,           osMessageQueueId_t)
 | |
| SVC0_1(MessageQueueGetSpace,    uint32_t,           osMessageQueueId_t)
 | |
| SVC0_1(MessageQueueReset,       osStatus_t,         osMessageQueueId_t)
 | |
| SVC0_1(MessageQueueDelete,      osStatus_t,         osMessageQueueId_t)
 | |
| //lint --flb "Library End"
 | |
| 
 | |
| 
 | |
| //  ==== ISR Calls ====
 | |
| 
 | |
| /// Put a Message into a Queue or timeout if Queue is full.
 | |
| /// \note API identical to osMessageQueuePut
 | |
| __STATIC_INLINE
 | |
| osStatus_t isrRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_message_t       *msg;
 | |
|   osStatus_t          status;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Try to allocate memory
 | |
|   //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
 | |
|   msg = osRtxMemoryPoolAlloc(&mq->mp_info);
 | |
|   if (msg != NULL) {
 | |
|     // Copy Message
 | |
|     memcpy(&msg[1], msg_ptr, mq->msg_size);
 | |
|     msg->id       = osRtxIdMessage;
 | |
|     msg->flags    = 0U;
 | |
|     msg->priority = msg_prio;
 | |
|     // Register post ISR processing
 | |
|     //lint -e{9079} -e{9087} "cast between pointers to different object types"
 | |
|     *((const void **)(void *)&msg->prev) = msg_ptr;
 | |
|     //lint -e{9079} -e{9087} "cast between pointers to different object types"
 | |
|     *(      (void **)        &msg->next) = mq;
 | |
|     osRtxPostProcess(osRtxObject(msg));
 | |
|     EvrRtxMessageQueueInsertPending(mq, msg_ptr);
 | |
|     status = osOK;
 | |
|   } else {
 | |
|     // No memory available
 | |
|     EvrRtxMessageQueueNotInserted(mq, msg_ptr);
 | |
|     status = osErrorResource;
 | |
|   }
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Get a Message from a Queue or timeout if Queue is empty.
 | |
| /// \note API identical to osMessageQueueGet
 | |
| __STATIC_INLINE
 | |
| osStatus_t isrRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
 | |
|   os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
 | |
|   os_message_t       *msg;
 | |
|   osStatus_t          status;
 | |
| 
 | |
|   // Check parameters
 | |
|   if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
 | |
|     EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
 | |
|     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
 | |
|     return osErrorParameter;
 | |
|   }
 | |
| 
 | |
|   // Get Message from Queue
 | |
|   msg = MessageQueueGet(mq);
 | |
|   if (msg != NULL) {
 | |
|     // Copy Message
 | |
|     memcpy(msg_ptr, &msg[1], mq->msg_size);
 | |
|     if (msg_prio != NULL) {
 | |
|       *msg_prio = msg->priority;
 | |
|     }
 | |
|     // Register post ISR processing
 | |
|     //lint -e{9079} -e{9087} "cast between pointers to different object types"
 | |
|     *((os_message_queue_t **)(void *)&msg[1]) = mq;
 | |
|     osRtxPostProcess(osRtxObject(msg));
 | |
|     EvrRtxMessageQueueRetrieved(mq, msg_ptr);
 | |
|     status = osOK;
 | |
|   } else {
 | |
|     // No Message available
 | |
|     EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
 | |
|     status = osErrorResource;
 | |
|   }
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| //  ==== Public API ====
 | |
| 
 | |
| /// Create and Initialize a Message Queue object.
 | |
| osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
 | |
|   osMessageQueueId_t mq_id;
 | |
| 
 | |
|   EvrRtxMessageQueueNew(msg_count, msg_size, attr);
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     EvrRtxMessageQueueError(NULL, (int32_t)osErrorISR);
 | |
|     mq_id = NULL;
 | |
|   } else {
 | |
|     mq_id = __svcMessageQueueNew(msg_count, msg_size, attr);
 | |
|   }
 | |
|   return mq_id;
 | |
| }
 | |
| 
 | |
| /// Get name of a Message Queue object.
 | |
| const char *osMessageQueueGetName (osMessageQueueId_t mq_id) {
 | |
|   const char *name;
 | |
| 
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     EvrRtxMessageQueueGetName(mq_id, NULL);
 | |
|     name = NULL;
 | |
|   } else {
 | |
|     name = __svcMessageQueueGetName(mq_id);
 | |
|   }
 | |
|   return name;
 | |
| }
 | |
| 
 | |
| /// Put a Message into a Queue or timeout if Queue is full.
 | |
| osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
 | |
|   osStatus_t status;
 | |
| 
 | |
|   EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   } else {
 | |
|     status =  __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   }
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Get a Message from a Queue or timeout if Queue is empty.
 | |
| osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
 | |
|   osStatus_t status;
 | |
| 
 | |
|   EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   } else {
 | |
|     status =  __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
 | |
|   }
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Get maximum number of messages in a Message Queue.
 | |
| uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
 | |
|   uint32_t capacity;
 | |
| 
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     capacity = svcRtxMessageQueueGetCapacity(mq_id);
 | |
|   } else {
 | |
|     capacity =  __svcMessageQueueGetCapacity(mq_id);
 | |
|   }
 | |
|   return capacity;
 | |
| }
 | |
| 
 | |
| /// Get maximum message size in a Memory Pool.
 | |
| uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
 | |
|   uint32_t msg_size;
 | |
| 
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     msg_size = svcRtxMessageQueueGetMsgSize(mq_id);
 | |
|   } else {
 | |
|     msg_size =  __svcMessageQueueGetMsgSize(mq_id);
 | |
|   }
 | |
|   return msg_size;
 | |
| }
 | |
| 
 | |
| /// Get number of queued messages in a Message Queue.
 | |
| uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
 | |
|   uint32_t count;
 | |
| 
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     count = svcRtxMessageQueueGetCount(mq_id);
 | |
|   } else {
 | |
|     count =  __svcMessageQueueGetCount(mq_id);
 | |
|   }
 | |
|   return count;
 | |
| }
 | |
| 
 | |
| /// Get number of available slots for messages in a Message Queue.
 | |
| uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
 | |
|   uint32_t space;
 | |
| 
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     space = svcRtxMessageQueueGetSpace(mq_id);
 | |
|   } else {
 | |
|     space =  __svcMessageQueueGetSpace(mq_id);
 | |
|   }
 | |
|   return space;
 | |
| }
 | |
| 
 | |
| /// Reset a Message Queue to initial empty state.
 | |
| osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
 | |
|   osStatus_t status;
 | |
| 
 | |
|   EvrRtxMessageQueueReset(mq_id);
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
 | |
|     status = osErrorISR;
 | |
|   } else {
 | |
|     status = __svcMessageQueueReset(mq_id);
 | |
|   }
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /// Delete a Message Queue object.
 | |
| osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
 | |
|   osStatus_t status;
 | |
| 
 | |
|   EvrRtxMessageQueueDelete(mq_id);
 | |
|   if (IsIrqMode() || IsIrqMasked()) {
 | |
|     EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
 | |
|     status = osErrorISR;
 | |
|   } else {
 | |
|     status = __svcMessageQueueDelete(mq_id);
 | |
|   }
 | |
|   return status;
 | |
| }
 | 
