Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more
queue.c
00001 /* 00002 FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. 00003 All rights reserved 00004 00005 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 00006 00007 *************************************************************************** 00008 * * 00009 * FreeRTOS provides completely free yet professionally developed, * 00010 * robust, strictly quality controlled, supported, and cross * 00011 * platform software that has become a de facto standard. * 00012 * * 00013 * Help yourself get started quickly and support the FreeRTOS * 00014 * project by purchasing a FreeRTOS tutorial book, reference * 00015 * manual, or both from: http://www.FreeRTOS.org/Documentation * 00016 * * 00017 * Thank you! * 00018 * * 00019 *************************************************************************** 00020 00021 This file is part of the FreeRTOS distribution. 00022 00023 FreeRTOS is free software; you can redistribute it and/or modify it under 00024 the terms of the GNU General Public License (version 2) as published by the 00025 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 00026 00027 >>! NOTE: The modification to the GPL is included to allow you to distribute 00028 >>! a combined work that includes FreeRTOS without being obliged to provide 00029 >>! the source code for proprietary components outside of the FreeRTOS 00030 >>! kernel. 00031 00032 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 00033 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00034 FOR A PARTICULAR PURPOSE. Full license text is available from the following 00035 link: http://www.freertos.org/a00114.html 00036 00037 1 tab == 4 spaces! 00038 00039 *************************************************************************** 00040 * * 00041 * Having a problem? Start by reading the FAQ "My application does * 00042 * not run, what could be wrong?" * 00043 * * 00044 * http://www.FreeRTOS.org/FAQHelp.html * 00045 * * 00046 *************************************************************************** 00047 00048 http://www.FreeRTOS.org - Documentation, books, training, latest versions, 00049 license and Real Time Engineers Ltd. contact details. 00050 00051 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 00052 including FreeRTOS+Trace - an indispensable productivity tool, a DOS 00053 compatible FAT file system, and our tiny thread aware UDP/IP stack. 00054 00055 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High 00056 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS 00057 licenses offer ticketed support, indemnification and middleware. 00058 00059 http://www.SafeRTOS.com - High Integrity Systems also provide a safety 00060 engineered and independently SIL3 certified version for use in safety and 00061 mission critical applications that require provable dependability. 00062 00063 1 tab == 4 spaces! 00064 */ 00065 00066 #include <stdlib.h> 00067 #include <string.h> 00068 00069 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining 00070 all the API functions to use the MPU wrappers. That should only be done when 00071 task.h is included from an application file. */ 00072 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE 00073 00074 #include "FreeRTOS.h" 00075 #include "task.h" 00076 #include "queue.h" 00077 00078 #if ( configUSE_CO_ROUTINES == 1 ) 00079 #include "croutine.h" 00080 #endif 00081 00082 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the 00083 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the 00084 header files above, but not in this file, in order to generate the correct 00085 privileged Vs unprivileged linkage and placement. */ 00086 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ 00087 00088 00089 /* Constants used with the cRxLock and xTxLock structure members. */ 00090 #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 ) 00091 #define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 ) 00092 00093 /* When the xQUEUE structure is used to represent a base queue its pcHead and 00094 pcTail members are used as pointers into the queue storage area. When the 00095 xQUEUE structure is used to represent a mutex pcHead and pcTail pointers are 00096 not necessary, and the pcHead pointer is set to NULL to indicate that the 00097 pcTail pointer actually points to the mutex holder (if any). Map alternative 00098 names to the pcHead and pcTail structure members to ensure the readability of 00099 the code is maintained despite this dual use of two structure members. An 00100 alternative implementation would be to use a union, but use of a union is 00101 against the coding standard (although an exception to the standard has been 00102 permitted where the dual use also significantly changes the type of the 00103 structure member). */ 00104 #define pxMutexHolder pcTail 00105 #define uxQueueType pcHead 00106 #define queueQUEUE_IS_MUTEX NULL 00107 00108 /* Semaphores do not actually store or copy data, so have an item size of 00109 zero. */ 00110 #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portBASE_TYPE ) 0 ) 00111 #define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0U ) 00112 00113 #if( configUSE_PREEMPTION == 0 ) 00114 /* If the cooperative scheduler is being used then a yield should not be 00115 performed just because a higher priority task has been woken. */ 00116 #define queueYIELD_IF_USING_PREEMPTION() 00117 #else 00118 #define queueYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() 00119 #endif 00120 00121 /* 00122 * Definition of the queue used by the scheduler. 00123 * Items are queued by copy, not reference. 00124 */ 00125 typedef struct QueueDefinition 00126 { 00127 signed char *pcHead; /*< Points to the beginning of the queue storage area. */ 00128 signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ 00129 00130 signed char *pcWriteTo; /*< Points to the free next place in the storage area. */ 00131 00132 union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */ 00133 { 00134 signed char *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ 00135 unsigned portBASE_TYPE uxRecursiveCallCount;/*< Maintains a count of the numebr of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ 00136 } u; 00137 00138 xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ 00139 xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */ 00140 00141 volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */ 00142 unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ 00143 unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */ 00144 00145 volatile signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ 00146 volatile signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ 00147 00148 #if ( configUSE_TRACE_FACILITY == 1 ) 00149 unsigned char ucQueueNumber; 00150 unsigned char ucQueueType; 00151 #endif 00152 00153 #if ( configUSE_QUEUE_SETS == 1 ) 00154 struct QueueDefinition *pxQueueSetContainer; 00155 #endif 00156 00157 } xQUEUE; 00158 /*-----------------------------------------------------------*/ 00159 00160 /* 00161 * The queue registry is just a means for kernel aware debuggers to locate 00162 * queue structures. It has no other purpose so is an optional component. 00163 */ 00164 #if ( configQUEUE_REGISTRY_SIZE > 0 ) 00165 00166 /* The type stored within the queue registry array. This allows a name 00167 to be assigned to each queue making kernel aware debugging a little 00168 more user friendly. */ 00169 typedef struct QUEUE_REGISTRY_ITEM 00170 { 00171 signed char *pcQueueName; 00172 xQueueHandle xHandle; 00173 } xQueueRegistryItem; 00174 00175 /* The queue registry is simply an array of xQueueRegistryItem structures. 00176 The pcQueueName member of a structure being NULL is indicative of the 00177 array position being vacant. */ 00178 xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; 00179 00180 #endif /* configQUEUE_REGISTRY_SIZE */ 00181 00182 /* 00183 * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not 00184 * prevent an ISR from adding or removing items to the queue, but does prevent 00185 * an ISR from removing tasks from the queue event lists. If an ISR finds a 00186 * queue is locked it will instead increment the appropriate queue lock count 00187 * to indicate that a task may require unblocking. When the queue in unlocked 00188 * these lock counts are inspected, and the appropriate action taken. 00189 */ 00190 static void prvUnlockQueue( xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; 00191 00192 /* 00193 * Uses a critical section to determine if there is any data in a queue. 00194 * 00195 * @return pdTRUE if the queue contains no items, otherwise pdFALSE. 00196 */ 00197 static signed portBASE_TYPE prvIsQueueEmpty( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; 00198 00199 /* 00200 * Uses a critical section to determine if there is any space in a queue. 00201 * 00202 * @return pdTRUE if there is no space, otherwise pdFALSE; 00203 */ 00204 static signed portBASE_TYPE prvIsQueueFull( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; 00205 00206 /* 00207 * Copies an item into the queue, either at the front of the queue or the 00208 * back of the queue. 00209 */ 00210 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION; 00211 00212 /* 00213 * Copies an item out of a queue. 00214 */ 00215 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; 00216 00217 #if ( configUSE_QUEUE_SETS == 1 ) 00218 /* 00219 * Checks to see if a queue is a member of a queue set, and if so, notifies 00220 * the queue set that the queue contains data. 00221 */ 00222 static portBASE_TYPE prvNotifyQueueSetContainer( const xQUEUE * const pxQueue, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; 00223 #endif 00224 00225 /*-----------------------------------------------------------*/ 00226 00227 /* 00228 * Macro to mark a queue as locked. Locking a queue prevents an ISR from 00229 * accessing the queue event lists. 00230 */ 00231 #define prvLockQueue( pxQueue ) \ 00232 taskENTER_CRITICAL(); \ 00233 { \ 00234 if( ( pxQueue )->xRxLock == queueUNLOCKED ) \ 00235 { \ 00236 ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \ 00237 } \ 00238 if( ( pxQueue )->xTxLock == queueUNLOCKED ) \ 00239 { \ 00240 ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \ 00241 } \ 00242 } \ 00243 taskEXIT_CRITICAL() 00244 /*-----------------------------------------------------------*/ 00245 00246 portBASE_TYPE xQueueGenericReset( xQueueHandle xQueue, portBASE_TYPE xNewQueue ) 00247 { 00248 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 00249 00250 configASSERT( pxQueue ); 00251 00252 taskENTER_CRITICAL(); 00253 { 00254 pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); 00255 pxQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; 00256 pxQueue->pcWriteTo = pxQueue->pcHead; 00257 pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( unsigned portBASE_TYPE ) 1U ) * pxQueue->uxItemSize ); 00258 pxQueue->xRxLock = queueUNLOCKED; 00259 pxQueue->xTxLock = queueUNLOCKED; 00260 00261 if( xNewQueue == pdFALSE ) 00262 { 00263 /* If there are tasks blocked waiting to read from the queue, then 00264 the tasks will remain blocked as after this function exits the queue 00265 will still be empty. If there are tasks blocked waiting to write to 00266 the queue, then one should be unblocked as after this function exits 00267 it will be possible to write to it. */ 00268 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 00269 { 00270 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) 00271 { 00272 queueYIELD_IF_USING_PREEMPTION(); 00273 } 00274 } 00275 } 00276 else 00277 { 00278 /* Ensure the event queues start in the correct state. */ 00279 vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); 00280 vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); 00281 } 00282 } 00283 taskEXIT_CRITICAL(); 00284 00285 /* A value is returned for calling semantic consistency with previous 00286 versions. */ 00287 return pdPASS; 00288 } 00289 /*-----------------------------------------------------------*/ 00290 00291 xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) 00292 { 00293 xQUEUE *pxNewQueue; 00294 size_t xQueueSizeInBytes; 00295 xQueueHandle xReturn = NULL; 00296 00297 /* Remove compiler warnings about unused parameters should 00298 configUSE_TRACE_FACILITY not be set to 1. */ 00299 ( void ) ucQueueType; 00300 00301 /* Allocate the new queue structure. */ 00302 if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 ) 00303 { 00304 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) ); 00305 if( pxNewQueue != NULL ) 00306 { 00307 /* Create the list of pointers to queue items. The queue is one byte 00308 longer than asked for to make wrap checking easier/faster. */ 00309 xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 00310 00311 pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes ); 00312 if( pxNewQueue->pcHead != NULL ) 00313 { 00314 /* Initialise the queue members as described above where the 00315 queue type is defined. */ 00316 pxNewQueue->uxLength = uxQueueLength; 00317 pxNewQueue->uxItemSize = uxItemSize; 00318 ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); 00319 00320 #if ( configUSE_TRACE_FACILITY == 1 ) 00321 { 00322 pxNewQueue->ucQueueType = ucQueueType; 00323 } 00324 #endif /* configUSE_TRACE_FACILITY */ 00325 00326 #if( configUSE_QUEUE_SETS == 1 ) 00327 { 00328 pxNewQueue->pxQueueSetContainer = NULL; 00329 } 00330 #endif /* configUSE_QUEUE_SETS */ 00331 00332 traceQUEUE_CREATE( pxNewQueue ); 00333 xReturn = pxNewQueue; 00334 } 00335 else 00336 { 00337 traceQUEUE_CREATE_FAILED( ucQueueType ); 00338 vPortFree( pxNewQueue ); 00339 } 00340 } 00341 } 00342 00343 configASSERT( xReturn ); 00344 00345 return xReturn; 00346 } 00347 /*-----------------------------------------------------------*/ 00348 00349 #if ( configUSE_MUTEXES == 1 ) 00350 00351 xQueueHandle xQueueCreateMutex( unsigned char ucQueueType ) 00352 { 00353 xQUEUE *pxNewQueue; 00354 00355 /* Prevent compiler warnings about unused parameters if 00356 configUSE_TRACE_FACILITY does not equal 1. */ 00357 ( void ) ucQueueType; 00358 00359 /* Allocate the new queue structure. */ 00360 pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) ); 00361 if( pxNewQueue != NULL ) 00362 { 00363 /* Information required for priority inheritance. */ 00364 pxNewQueue->pxMutexHolder = NULL; 00365 pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; 00366 00367 /* Queues used as a mutex no data is actually copied into or out 00368 of the queue. */ 00369 pxNewQueue->pcWriteTo = NULL; 00370 pxNewQueue->u.pcReadFrom = NULL; 00371 00372 /* Each mutex has a length of 1 (like a binary semaphore) and 00373 an item size of 0 as nothing is actually copied into or out 00374 of the mutex. */ 00375 pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; 00376 pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U; 00377 pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U; 00378 pxNewQueue->xRxLock = queueUNLOCKED; 00379 pxNewQueue->xTxLock = queueUNLOCKED; 00380 00381 #if ( configUSE_TRACE_FACILITY == 1 ) 00382 { 00383 pxNewQueue->ucQueueType = ucQueueType; 00384 } 00385 #endif 00386 00387 #if ( configUSE_QUEUE_SETS == 1 ) 00388 { 00389 pxNewQueue->pxQueueSetContainer = NULL; 00390 } 00391 #endif 00392 00393 /* Ensure the event queues start with the correct state. */ 00394 vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); 00395 vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); 00396 00397 traceCREATE_MUTEX( pxNewQueue ); 00398 00399 /* Start with the semaphore in the expected state. */ 00400 ( void ) xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK ); 00401 } 00402 else 00403 { 00404 traceCREATE_MUTEX_FAILED(); 00405 } 00406 00407 configASSERT( pxNewQueue ); 00408 return pxNewQueue; 00409 } 00410 00411 #endif /* configUSE_MUTEXES */ 00412 /*-----------------------------------------------------------*/ 00413 00414 #if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) 00415 00416 void* xQueueGetMutexHolder( xQueueHandle xSemaphore ) 00417 { 00418 void *pxReturn; 00419 00420 /* This function is called by xSemaphoreGetMutexHolder(), and should not 00421 be called directly. Note: This is is a good way of determining if the 00422 calling task is the mutex holder, but not a good way of determining the 00423 identity of the mutex holder, as the holder may change between the 00424 following critical section exiting and the function returning. */ 00425 taskENTER_CRITICAL(); 00426 { 00427 if( ( ( xQUEUE * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) 00428 { 00429 pxReturn = ( void * ) ( ( xQUEUE * ) xSemaphore )->pxMutexHolder; 00430 } 00431 else 00432 { 00433 pxReturn = NULL; 00434 } 00435 } 00436 taskEXIT_CRITICAL(); 00437 00438 return pxReturn; 00439 } 00440 00441 #endif 00442 /*-----------------------------------------------------------*/ 00443 00444 #if ( configUSE_RECURSIVE_MUTEXES == 1 ) 00445 00446 portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) 00447 { 00448 portBASE_TYPE xReturn; 00449 xQUEUE * const pxMutex = ( xQUEUE * ) xMutex; 00450 00451 configASSERT( pxMutex ); 00452 00453 /* If this is the task that holds the mutex then pxMutexHolder will not 00454 change outside of this task. If this task does not hold the mutex then 00455 pxMutexHolder can never coincidentally equal the tasks handle, and as 00456 this is the only condition we are interested in it does not matter if 00457 pxMutexHolder is accessed simultaneously by another task. Therefore no 00458 mutual exclusion is required to test the pxMutexHolder variable. */ 00459 if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as xTaskHandle is a typedef. */ 00460 { 00461 traceGIVE_MUTEX_RECURSIVE( pxMutex ); 00462 00463 /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to 00464 the task handle, therefore no underflow check is required. Also, 00465 uxRecursiveCallCount is only modified by the mutex holder, and as 00466 there can only be one, no mutual exclusion is required to modify the 00467 uxRecursiveCallCount member. */ 00468 ( pxMutex->u.uxRecursiveCallCount )--; 00469 00470 /* Have we unwound the call count? */ 00471 if( pxMutex->u.uxRecursiveCallCount == ( unsigned portBASE_TYPE ) 0 ) 00472 { 00473 /* Return the mutex. This will automatically unblock any other 00474 task that might be waiting to access the mutex. */ 00475 ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); 00476 } 00477 00478 xReturn = pdPASS; 00479 } 00480 else 00481 { 00482 /* We cannot give the mutex because we are not the holder. */ 00483 xReturn = pdFAIL; 00484 00485 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); 00486 } 00487 00488 return xReturn; 00489 } 00490 00491 #endif /* configUSE_RECURSIVE_MUTEXES */ 00492 /*-----------------------------------------------------------*/ 00493 00494 #if ( configUSE_RECURSIVE_MUTEXES == 1 ) 00495 00496 portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) 00497 { 00498 portBASE_TYPE xReturn; 00499 xQUEUE * const pxMutex = ( xQUEUE * ) xMutex; 00500 00501 configASSERT( pxMutex ); 00502 00503 /* Comments regarding mutual exclusion as per those within 00504 xQueueGiveMutexRecursive(). */ 00505 00506 traceTAKE_MUTEX_RECURSIVE( pxMutex ); 00507 00508 if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as xTaskHandle is a typedef. */ 00509 { 00510 ( pxMutex->u.uxRecursiveCallCount )++; 00511 xReturn = pdPASS; 00512 } 00513 else 00514 { 00515 xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE ); 00516 00517 /* pdPASS will only be returned if we successfully obtained the mutex, 00518 we may have blocked to reach here. */ 00519 if( xReturn == pdPASS ) 00520 { 00521 ( pxMutex->u.uxRecursiveCallCount )++; 00522 } 00523 else 00524 { 00525 traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); 00526 } 00527 } 00528 00529 return xReturn; 00530 } 00531 00532 #endif /* configUSE_RECURSIVE_MUTEXES */ 00533 /*-----------------------------------------------------------*/ 00534 00535 #if ( configUSE_COUNTING_SEMAPHORES == 1 ) 00536 00537 xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount ) 00538 { 00539 xQueueHandle xHandle; 00540 00541 configASSERT( uxMaxCount != 0 ); 00542 configASSERT( uxInitialCount <= uxMaxCount ); 00543 00544 xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); 00545 00546 if( xHandle != NULL ) 00547 { 00548 ( ( xQUEUE * ) xHandle )->uxMessagesWaiting = uxInitialCount; 00549 00550 traceCREATE_COUNTING_SEMAPHORE(); 00551 } 00552 else 00553 { 00554 traceCREATE_COUNTING_SEMAPHORE_FAILED(); 00555 } 00556 00557 configASSERT( xHandle ); 00558 return xHandle; 00559 } 00560 00561 #endif /* configUSE_COUNTING_SEMAPHORES */ 00562 /*-----------------------------------------------------------*/ 00563 00564 signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) 00565 { 00566 signed portBASE_TYPE xEntryTimeSet = pdFALSE; 00567 xTimeOutType xTimeOut; 00568 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 00569 00570 configASSERT( pxQueue ); 00571 configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 00572 configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); 00573 00574 /* This function relaxes the coding standard somewhat to allow return 00575 statements within the function itself. This is done in the interest 00576 of execution time efficiency. */ 00577 for( ;; ) 00578 { 00579 taskENTER_CRITICAL(); 00580 { 00581 /* Is there room on the queue now? The running task must be 00582 the highest priority task wanting to access the queue. If 00583 the head item in the queue is to be overwritten then it does 00584 not matter if the queue is full. */ 00585 if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) 00586 { 00587 traceQUEUE_SEND( pxQueue ); 00588 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); 00589 00590 #if ( configUSE_QUEUE_SETS == 1 ) 00591 { 00592 if( pxQueue->pxQueueSetContainer != NULL ) 00593 { 00594 if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) 00595 { 00596 /* The queue is a member of a queue set, and posting 00597 to the queue set caused a higher priority task to 00598 unblock. A context switch is required. */ 00599 queueYIELD_IF_USING_PREEMPTION(); 00600 } 00601 } 00602 else 00603 { 00604 /* If there was a task waiting for data to arrive on the 00605 queue then unblock it now. */ 00606 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 00607 { 00608 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) 00609 { 00610 /* The unblocked task has a priority higher than 00611 our own so yield immediately. Yes it is ok to 00612 do this from within the critical section - the 00613 kernel takes care of that. */ 00614 queueYIELD_IF_USING_PREEMPTION(); 00615 } 00616 } 00617 } 00618 } 00619 #else /* configUSE_QUEUE_SETS */ 00620 { 00621 /* If there was a task waiting for data to arrive on the 00622 queue then unblock it now. */ 00623 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 00624 { 00625 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) 00626 { 00627 /* The unblocked task has a priority higher than 00628 our own so yield immediately. Yes it is ok to do 00629 this from within the critical section - the kernel 00630 takes care of that. */ 00631 queueYIELD_IF_USING_PREEMPTION(); 00632 } 00633 } 00634 } 00635 #endif /* configUSE_QUEUE_SETS */ 00636 00637 taskEXIT_CRITICAL(); 00638 00639 /* Return to the original privilege level before exiting the 00640 function. */ 00641 return pdPASS; 00642 } 00643 else 00644 { 00645 if( xTicksToWait == ( portTickType ) 0 ) 00646 { 00647 /* The queue was full and no block time is specified (or 00648 the block time has expired) so leave now. */ 00649 taskEXIT_CRITICAL(); 00650 00651 /* Return to the original privilege level before exiting 00652 the function. */ 00653 traceQUEUE_SEND_FAILED( pxQueue ); 00654 return errQUEUE_FULL; 00655 } 00656 else if( xEntryTimeSet == pdFALSE ) 00657 { 00658 /* The queue was full and a block time was specified so 00659 configure the timeout structure. */ 00660 vTaskSetTimeOutState( &xTimeOut ); 00661 xEntryTimeSet = pdTRUE; 00662 } 00663 else 00664 { 00665 /* Entry time was already set. */ 00666 } 00667 } 00668 } 00669 taskEXIT_CRITICAL(); 00670 00671 /* Interrupts and other tasks can send to and receive from the queue 00672 now the critical section has been exited. */ 00673 00674 vTaskSuspendAll(); 00675 prvLockQueue( pxQueue ); 00676 00677 /* Update the timeout state to see if it has expired yet. */ 00678 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 00679 { 00680 if( prvIsQueueFull( pxQueue ) != pdFALSE ) 00681 { 00682 traceBLOCKING_ON_QUEUE_SEND( pxQueue ); 00683 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); 00684 00685 /* Unlocking the queue means queue events can effect the 00686 event list. It is possible that interrupts occurring now 00687 remove this task from the event list again - but as the 00688 scheduler is suspended the task will go onto the pending 00689 ready last instead of the actual ready list. */ 00690 prvUnlockQueue( pxQueue ); 00691 00692 /* Resuming the scheduler will move tasks from the pending 00693 ready list into the ready list - so it is feasible that this 00694 task is already in a ready list before it yields - in which 00695 case the yield will not cause a context switch unless there 00696 is also a higher priority task in the pending ready list. */ 00697 if( xTaskResumeAll() == pdFALSE ) 00698 { 00699 portYIELD_WITHIN_API(); 00700 } 00701 } 00702 else 00703 { 00704 /* Try again. */ 00705 prvUnlockQueue( pxQueue ); 00706 ( void ) xTaskResumeAll(); 00707 } 00708 } 00709 else 00710 { 00711 /* The timeout has expired. */ 00712 prvUnlockQueue( pxQueue ); 00713 ( void ) xTaskResumeAll(); 00714 00715 /* Return to the original privilege level before exiting the 00716 function. */ 00717 traceQUEUE_SEND_FAILED( pxQueue ); 00718 return errQUEUE_FULL; 00719 } 00720 } 00721 } 00722 /*-----------------------------------------------------------*/ 00723 00724 #if ( configUSE_ALTERNATIVE_API == 1 ) 00725 00726 signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) 00727 { 00728 signed portBASE_TYPE xEntryTimeSet = pdFALSE; 00729 xTimeOutType xTimeOut; 00730 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 00731 00732 configASSERT( pxQueue ); 00733 configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 00734 00735 for( ;; ) 00736 { 00737 taskENTER_CRITICAL(); 00738 { 00739 /* Is there room on the queue now? To be running we must be 00740 the highest priority task wanting to access the queue. */ 00741 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) 00742 { 00743 traceQUEUE_SEND( pxQueue ); 00744 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); 00745 00746 /* If there was a task waiting for data to arrive on the 00747 queue then unblock it now. */ 00748 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 00749 { 00750 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) 00751 { 00752 /* The unblocked task has a priority higher than 00753 our own so yield immediately. */ 00754 portYIELD_WITHIN_API(); 00755 } 00756 } 00757 00758 taskEXIT_CRITICAL(); 00759 return pdPASS; 00760 } 00761 else 00762 { 00763 if( xTicksToWait == ( portTickType ) 0 ) 00764 { 00765 taskEXIT_CRITICAL(); 00766 return errQUEUE_FULL; 00767 } 00768 else if( xEntryTimeSet == pdFALSE ) 00769 { 00770 vTaskSetTimeOutState( &xTimeOut ); 00771 xEntryTimeSet = pdTRUE; 00772 } 00773 } 00774 } 00775 taskEXIT_CRITICAL(); 00776 00777 taskENTER_CRITICAL(); 00778 { 00779 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 00780 { 00781 if( prvIsQueueFull( pxQueue ) != pdFALSE ) 00782 { 00783 traceBLOCKING_ON_QUEUE_SEND( pxQueue ); 00784 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); 00785 portYIELD_WITHIN_API(); 00786 } 00787 } 00788 else 00789 { 00790 taskEXIT_CRITICAL(); 00791 traceQUEUE_SEND_FAILED( pxQueue ); 00792 return errQUEUE_FULL; 00793 } 00794 } 00795 taskEXIT_CRITICAL(); 00796 } 00797 } 00798 00799 #endif /* configUSE_ALTERNATIVE_API */ 00800 /*-----------------------------------------------------------*/ 00801 00802 #if ( configUSE_ALTERNATIVE_API == 1 ) 00803 00804 signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) 00805 { 00806 signed portBASE_TYPE xEntryTimeSet = pdFALSE; 00807 xTimeOutType xTimeOut; 00808 signed char *pcOriginalReadPosition; 00809 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 00810 00811 configASSERT( pxQueue ); 00812 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 00813 00814 for( ;; ) 00815 { 00816 taskENTER_CRITICAL(); 00817 { 00818 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 00819 { 00820 /* Remember our read position in case we are just peeking. */ 00821 pcOriginalReadPosition = pxQueue->u.pcReadFrom; 00822 00823 prvCopyDataFromQueue( pxQueue, pvBuffer ); 00824 00825 if( xJustPeeking == pdFALSE ) 00826 { 00827 traceQUEUE_RECEIVE( pxQueue ); 00828 00829 /* Data is actually being removed (not just peeked). */ 00830 --( pxQueue->uxMessagesWaiting ); 00831 00832 #if ( configUSE_MUTEXES == 1 ) 00833 { 00834 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 00835 { 00836 /* Record the information required to implement 00837 priority inheritance should it become necessary. */ 00838 pxQueue->pxMutexHolder = ( signed char * ) xTaskGetCurrentTaskHandle(); 00839 } 00840 } 00841 #endif 00842 00843 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 00844 { 00845 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) 00846 { 00847 portYIELD_WITHIN_API(); 00848 } 00849 } 00850 } 00851 else 00852 { 00853 traceQUEUE_PEEK( pxQueue ); 00854 00855 /* We are not removing the data, so reset our read 00856 pointer. */ 00857 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 00858 00859 /* The data is being left in the queue, so see if there are 00860 any other tasks waiting for the data. */ 00861 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 00862 { 00863 /* Tasks that are removed from the event list will get added to 00864 the pending ready list as the scheduler is still suspended. */ 00865 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 00866 { 00867 /* The task waiting has a higher priority than this task. */ 00868 portYIELD_WITHIN_API(); 00869 } 00870 } 00871 00872 } 00873 00874 taskEXIT_CRITICAL(); 00875 return pdPASS; 00876 } 00877 else 00878 { 00879 if( xTicksToWait == ( portTickType ) 0 ) 00880 { 00881 taskEXIT_CRITICAL(); 00882 traceQUEUE_RECEIVE_FAILED( pxQueue ); 00883 return errQUEUE_EMPTY; 00884 } 00885 else if( xEntryTimeSet == pdFALSE ) 00886 { 00887 vTaskSetTimeOutState( &xTimeOut ); 00888 xEntryTimeSet = pdTRUE; 00889 } 00890 } 00891 } 00892 taskEXIT_CRITICAL(); 00893 00894 taskENTER_CRITICAL(); 00895 { 00896 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 00897 { 00898 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 00899 { 00900 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); 00901 00902 #if ( configUSE_MUTEXES == 1 ) 00903 { 00904 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 00905 { 00906 portENTER_CRITICAL(); 00907 { 00908 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); 00909 } 00910 portEXIT_CRITICAL(); 00911 } 00912 } 00913 #endif 00914 00915 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); 00916 portYIELD_WITHIN_API(); 00917 } 00918 } 00919 else 00920 { 00921 taskEXIT_CRITICAL(); 00922 traceQUEUE_RECEIVE_FAILED( pxQueue ); 00923 return errQUEUE_EMPTY; 00924 } 00925 } 00926 taskEXIT_CRITICAL(); 00927 } 00928 } 00929 00930 00931 #endif /* configUSE_ALTERNATIVE_API */ 00932 /*-----------------------------------------------------------*/ 00933 00934 signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle xQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) 00935 { 00936 signed portBASE_TYPE xReturn; 00937 unsigned portBASE_TYPE uxSavedInterruptStatus; 00938 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 00939 00940 configASSERT( pxQueue ); 00941 configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 00942 configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); 00943 00944 /* RTOS ports that support interrupt nesting have the concept of a maximum 00945 system call (or maximum API call) interrupt priority. Interrupts that are 00946 above the maximum system call priority are keep permanently enabled, even 00947 when the RTOS kernel is in a critical section, but cannot make any calls to 00948 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h 00949 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 00950 failure if a FreeRTOS API function is called from an interrupt that has been 00951 assigned a priority above the configured maximum system call priority. 00952 Only FreeRTOS functions that end in FromISR can be called from interrupts 00953 that have been assigned a priority at or (logically) below the maximum 00954 system call interrupt priority. FreeRTOS maintains a separate interrupt 00955 safe API to ensure interrupt entry is as fast and as simple as possible. 00956 More information (albeit Cortex-M specific) is provided on the following 00957 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 00958 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 00959 00960 /* Similar to xQueueGenericSend, except we don't block if there is no room 00961 in the queue. Also we don't directly wake a task that was blocked on a 00962 queue read, instead we return a flag to say whether a context switch is 00963 required or not (i.e. has a task with a higher priority than us been woken 00964 by this post). */ 00965 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 00966 { 00967 if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) 00968 { 00969 traceQUEUE_SEND_FROM_ISR( pxQueue ); 00970 00971 prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); 00972 00973 /* If the queue is locked we do not alter the event list. This will 00974 be done when the queue is unlocked later. */ 00975 if( pxQueue->xTxLock == queueUNLOCKED ) 00976 { 00977 #if ( configUSE_QUEUE_SETS == 1 ) 00978 { 00979 if( pxQueue->pxQueueSetContainer != NULL ) 00980 { 00981 if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) 00982 { 00983 /* The queue is a member of a queue set, and posting 00984 to the queue set caused a higher priority task to 00985 unblock. A context switch is required. */ 00986 if( pxHigherPriorityTaskWoken != NULL ) 00987 { 00988 *pxHigherPriorityTaskWoken = pdTRUE; 00989 } 00990 } 00991 } 00992 else 00993 { 00994 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 00995 { 00996 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 00997 { 00998 /* The task waiting has a higher priority so record that a 00999 context switch is required. */ 01000 if( pxHigherPriorityTaskWoken != NULL ) 01001 { 01002 *pxHigherPriorityTaskWoken = pdTRUE; 01003 } 01004 } 01005 } 01006 } 01007 } 01008 #else /* configUSE_QUEUE_SETS */ 01009 { 01010 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01011 { 01012 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01013 { 01014 /* The task waiting has a higher priority so record that a 01015 context switch is required. */ 01016 if( pxHigherPriorityTaskWoken != NULL ) 01017 { 01018 *pxHigherPriorityTaskWoken = pdTRUE; 01019 } 01020 } 01021 } 01022 } 01023 #endif /* configUSE_QUEUE_SETS */ 01024 } 01025 else 01026 { 01027 /* Increment the lock count so the task that unlocks the queue 01028 knows that data was posted while it was locked. */ 01029 ++( pxQueue->xTxLock ); 01030 } 01031 01032 xReturn = pdPASS; 01033 } 01034 else 01035 { 01036 traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); 01037 xReturn = errQUEUE_FULL; 01038 } 01039 } 01040 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01041 01042 return xReturn; 01043 } 01044 /*-----------------------------------------------------------*/ 01045 01046 signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) 01047 { 01048 signed portBASE_TYPE xEntryTimeSet = pdFALSE; 01049 xTimeOutType xTimeOut; 01050 signed char *pcOriginalReadPosition; 01051 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01052 01053 configASSERT( pxQueue ); 01054 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 01055 01056 /* This function relaxes the coding standard somewhat to allow return 01057 statements within the function itself. This is done in the interest 01058 of execution time efficiency. */ 01059 01060 for( ;; ) 01061 { 01062 taskENTER_CRITICAL(); 01063 { 01064 /* Is there data in the queue now? To be running we must be 01065 the highest priority task wanting to access the queue. */ 01066 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01067 { 01068 /* Remember the read position in case the queue is only being 01069 peeked. */ 01070 pcOriginalReadPosition = pxQueue->u.pcReadFrom; 01071 01072 prvCopyDataFromQueue( pxQueue, pvBuffer ); 01073 01074 if( xJustPeeking == pdFALSE ) 01075 { 01076 traceQUEUE_RECEIVE( pxQueue ); 01077 01078 /* Actually removing data, not just peeking. */ 01079 --( pxQueue->uxMessagesWaiting ); 01080 01081 #if ( configUSE_MUTEXES == 1 ) 01082 { 01083 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 01084 { 01085 /* Record the information required to implement 01086 priority inheritance should it become necessary. */ 01087 pxQueue->pxMutexHolder = ( signed char * ) xTaskGetCurrentTaskHandle(); /*lint !e961 Cast is not redundant as xTaskHandle is a typedef. */ 01088 } 01089 } 01090 #endif 01091 01092 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 01093 { 01094 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) 01095 { 01096 queueYIELD_IF_USING_PREEMPTION(); 01097 } 01098 } 01099 } 01100 else 01101 { 01102 traceQUEUE_PEEK( pxQueue ); 01103 01104 /* The data is not being removed, so reset the read 01105 pointer. */ 01106 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 01107 01108 /* The data is being left in the queue, so see if there are 01109 any other tasks waiting for the data. */ 01110 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01111 { 01112 /* Tasks that are removed from the event list will get added to 01113 the pending ready list as the scheduler is still suspended. */ 01114 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01115 { 01116 /* The task waiting has a higher priority than this task. */ 01117 queueYIELD_IF_USING_PREEMPTION(); 01118 } 01119 } 01120 } 01121 01122 taskEXIT_CRITICAL(); 01123 return pdPASS; 01124 } 01125 else 01126 { 01127 if( xTicksToWait == ( portTickType ) 0 ) 01128 { 01129 /* The queue was empty and no block time is specified (or 01130 the block time has expired) so leave now. */ 01131 taskEXIT_CRITICAL(); 01132 traceQUEUE_RECEIVE_FAILED( pxQueue ); 01133 return errQUEUE_EMPTY; 01134 } 01135 else if( xEntryTimeSet == pdFALSE ) 01136 { 01137 /* The queue was empty and a block time was specified so 01138 configure the timeout structure. */ 01139 vTaskSetTimeOutState( &xTimeOut ); 01140 xEntryTimeSet = pdTRUE; 01141 } 01142 else 01143 { 01144 /* Entry time was already set. */ 01145 } 01146 } 01147 } 01148 taskEXIT_CRITICAL(); 01149 01150 /* Interrupts and other tasks can send to and receive from the queue 01151 now the critical section has been exited. */ 01152 01153 vTaskSuspendAll(); 01154 prvLockQueue( pxQueue ); 01155 01156 /* Update the timeout state to see if it has expired yet. */ 01157 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 01158 { 01159 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 01160 { 01161 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); 01162 01163 #if ( configUSE_MUTEXES == 1 ) 01164 { 01165 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 01166 { 01167 portENTER_CRITICAL(); 01168 { 01169 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); 01170 } 01171 portEXIT_CRITICAL(); 01172 } 01173 } 01174 #endif 01175 01176 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); 01177 prvUnlockQueue( pxQueue ); 01178 if( xTaskResumeAll() == pdFALSE ) 01179 { 01180 portYIELD_WITHIN_API(); 01181 } 01182 } 01183 else 01184 { 01185 /* Try again. */ 01186 prvUnlockQueue( pxQueue ); 01187 ( void ) xTaskResumeAll(); 01188 } 01189 } 01190 else 01191 { 01192 prvUnlockQueue( pxQueue ); 01193 ( void ) xTaskResumeAll(); 01194 traceQUEUE_RECEIVE_FAILED( pxQueue ); 01195 return errQUEUE_EMPTY; 01196 } 01197 } 01198 } 01199 /*-----------------------------------------------------------*/ 01200 01201 signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle xQueue, void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken ) 01202 { 01203 signed portBASE_TYPE xReturn; 01204 unsigned portBASE_TYPE uxSavedInterruptStatus; 01205 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01206 01207 configASSERT( pxQueue ); 01208 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 01209 01210 /* RTOS ports that support interrupt nesting have the concept of a maximum 01211 system call (or maximum API call) interrupt priority. Interrupts that are 01212 above the maximum system call priority are keep permanently enabled, even 01213 when the RTOS kernel is in a critical section, but cannot make any calls to 01214 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h 01215 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01216 failure if a FreeRTOS API function is called from an interrupt that has been 01217 assigned a priority above the configured maximum system call priority. 01218 Only FreeRTOS functions that end in FromISR can be called from interrupts 01219 that have been assigned a priority at or (logically) below the maximum 01220 system call interrupt priority. FreeRTOS maintains a separate interrupt 01221 safe API to ensure interrupt entry is as fast and as simple as possible. 01222 More information (albeit Cortex-M specific) is provided on the following 01223 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01224 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01225 01226 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 01227 { 01228 /* Cannot block in an ISR, so check there is data available. */ 01229 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01230 { 01231 traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); 01232 01233 prvCopyDataFromQueue( pxQueue, pvBuffer ); 01234 --( pxQueue->uxMessagesWaiting ); 01235 01236 /* If the queue is locked the event list will not be modified. 01237 Instead update the lock count so the task that unlocks the queue 01238 will know that an ISR has removed data while the queue was 01239 locked. */ 01240 if( pxQueue->xRxLock == queueUNLOCKED ) 01241 { 01242 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 01243 { 01244 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 01245 { 01246 /* The task waiting has a higher priority than us so 01247 force a context switch. */ 01248 if( pxHigherPriorityTaskWoken != NULL ) 01249 { 01250 *pxHigherPriorityTaskWoken = pdTRUE; 01251 } 01252 } 01253 } 01254 } 01255 else 01256 { 01257 /* Increment the lock count so the task that unlocks the queue 01258 knows that data was removed while it was locked. */ 01259 ++( pxQueue->xRxLock ); 01260 } 01261 01262 xReturn = pdPASS; 01263 } 01264 else 01265 { 01266 xReturn = pdFAIL; 01267 traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); 01268 } 01269 } 01270 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01271 01272 return xReturn; 01273 } 01274 /*-----------------------------------------------------------*/ 01275 01276 signed portBASE_TYPE xQueuePeekFromISR( xQueueHandle xQueue, void * const pvBuffer ) 01277 { 01278 signed portBASE_TYPE xReturn; 01279 unsigned portBASE_TYPE uxSavedInterruptStatus; 01280 signed char *pcOriginalReadPosition; 01281 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01282 01283 configASSERT( pxQueue ); 01284 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); 01285 01286 /* RTOS ports that support interrupt nesting have the concept of a maximum 01287 system call (or maximum API call) interrupt priority. Interrupts that are 01288 above the maximum system call priority are keep permanently enabled, even 01289 when the RTOS kernel is in a critical section, but cannot make any calls to 01290 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h 01291 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01292 failure if a FreeRTOS API function is called from an interrupt that has been 01293 assigned a priority above the configured maximum system call priority. 01294 Only FreeRTOS functions that end in FromISR can be called from interrupts 01295 that have been assigned a priority at or (logically) below the maximum 01296 system call interrupt priority. FreeRTOS maintains a separate interrupt 01297 safe API to ensure interrupt entry is as fast and as simple as possible. 01298 More information (albeit Cortex-M specific) is provided on the following 01299 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01300 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01301 01302 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 01303 { 01304 /* Cannot block in an ISR, so check there is data available. */ 01305 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01306 { 01307 traceQUEUE_PEEK_FROM_ISR( pxQueue ); 01308 01309 /* Remember the read position so it can be reset as nothing is 01310 actually being removed from the queue. */ 01311 pcOriginalReadPosition = pxQueue->u.pcReadFrom; 01312 prvCopyDataFromQueue( pxQueue, pvBuffer ); 01313 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 01314 01315 xReturn = pdPASS; 01316 } 01317 else 01318 { 01319 xReturn = pdFAIL; 01320 traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ); 01321 } 01322 } 01323 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01324 01325 return xReturn; 01326 } 01327 /*-----------------------------------------------------------*/ 01328 01329 unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue ) 01330 { 01331 unsigned portBASE_TYPE uxReturn; 01332 01333 configASSERT( xQueue ); 01334 01335 taskENTER_CRITICAL(); 01336 uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting; 01337 taskEXIT_CRITICAL(); 01338 01339 return uxReturn; 01340 } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ 01341 /*-----------------------------------------------------------*/ 01342 01343 unsigned portBASE_TYPE uxQueueSpacesAvailable( const xQueueHandle xQueue ) 01344 { 01345 unsigned portBASE_TYPE uxReturn; 01346 xQUEUE *pxQueue; 01347 01348 pxQueue = ( xQUEUE * ) xQueue; 01349 configASSERT( pxQueue ); 01350 01351 taskENTER_CRITICAL(); 01352 uxReturn = pxQueue->uxLength - pxQueue->uxMessagesWaiting; 01353 taskEXIT_CRITICAL(); 01354 01355 return uxReturn; 01356 } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ 01357 /*-----------------------------------------------------------*/ 01358 01359 unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle xQueue ) 01360 { 01361 unsigned portBASE_TYPE uxReturn; 01362 01363 configASSERT( xQueue ); 01364 01365 uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting; 01366 01367 return uxReturn; 01368 } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ 01369 /*-----------------------------------------------------------*/ 01370 01371 void vQueueDelete( xQueueHandle xQueue ) 01372 { 01373 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01374 01375 configASSERT( pxQueue ); 01376 01377 traceQUEUE_DELETE( pxQueue ); 01378 #if ( configQUEUE_REGISTRY_SIZE > 0 ) 01379 { 01380 vQueueUnregisterQueue( pxQueue ); 01381 } 01382 #endif 01383 vPortFree( pxQueue->pcHead ); 01384 vPortFree( pxQueue ); 01385 } 01386 /*-----------------------------------------------------------*/ 01387 01388 #if ( configUSE_TRACE_FACILITY == 1 ) 01389 01390 unsigned char ucQueueGetQueueNumber( xQueueHandle xQueue ) 01391 { 01392 return ( ( xQUEUE * ) xQueue )->ucQueueNumber; 01393 } 01394 01395 #endif /* configUSE_TRACE_FACILITY */ 01396 /*-----------------------------------------------------------*/ 01397 01398 #if ( configUSE_TRACE_FACILITY == 1 ) 01399 01400 void vQueueSetQueueNumber( xQueueHandle xQueue, unsigned char ucQueueNumber ) 01401 { 01402 ( ( xQUEUE * ) xQueue )->ucQueueNumber = ucQueueNumber; 01403 } 01404 01405 #endif /* configUSE_TRACE_FACILITY */ 01406 /*-----------------------------------------------------------*/ 01407 01408 #if ( configUSE_TRACE_FACILITY == 1 ) 01409 01410 unsigned char ucQueueGetQueueType( xQueueHandle xQueue ) 01411 { 01412 return ( ( xQUEUE * ) xQueue )->ucQueueType; 01413 } 01414 01415 #endif /* configUSE_TRACE_FACILITY */ 01416 /*-----------------------------------------------------------*/ 01417 01418 static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) 01419 { 01420 if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 ) 01421 { 01422 #if ( configUSE_MUTEXES == 1 ) 01423 { 01424 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 01425 { 01426 /* The mutex is no longer being held. */ 01427 vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); 01428 pxQueue->pxMutexHolder = NULL; 01429 } 01430 } 01431 #endif /* configUSE_MUTEXES */ 01432 } 01433 else if( xPosition == queueSEND_TO_BACK ) 01434 { 01435 ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. */ 01436 pxQueue->pcWriteTo += pxQueue->uxItemSize; 01437 if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ 01438 { 01439 pxQueue->pcWriteTo = pxQueue->pcHead; 01440 } 01441 } 01442 else 01443 { 01444 ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 01445 pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; 01446 if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ 01447 { 01448 pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); 01449 } 01450 01451 if( xPosition == queueOVERWRITE ) 01452 { 01453 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01454 { 01455 /* An item is not being added but overwritten, so subtract 01456 one from the recorded number of items in the queue so when 01457 one is added again below the number of recorded items remains 01458 correct. */ 01459 --( pxQueue->uxMessagesWaiting ); 01460 } 01461 } 01462 } 01463 01464 ++( pxQueue->uxMessagesWaiting ); 01465 } 01466 /*-----------------------------------------------------------*/ 01467 01468 static void prvCopyDataFromQueue( xQUEUE * const pxQueue, void * const pvBuffer ) 01469 { 01470 if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX ) 01471 { 01472 pxQueue->u.pcReadFrom += pxQueue->uxItemSize; 01473 if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ 01474 { 01475 pxQueue->u.pcReadFrom = pxQueue->pcHead; 01476 } 01477 ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ 01478 } 01479 } 01480 /*-----------------------------------------------------------*/ 01481 01482 static void prvUnlockQueue( xQUEUE *pxQueue ) 01483 { 01484 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ 01485 01486 /* The lock counts contains the number of extra data items placed or 01487 removed from the queue while the queue was locked. When a queue is 01488 locked items can be added or removed, but the event lists cannot be 01489 updated. */ 01490 taskENTER_CRITICAL(); 01491 { 01492 /* See if data was added to the queue while it was locked. */ 01493 while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED ) 01494 { 01495 /* Data was posted while the queue was locked. Are any tasks 01496 blocked waiting for data to become available? */ 01497 #if ( configUSE_QUEUE_SETS == 1 ) 01498 { 01499 if( pxQueue->pxQueueSetContainer != NULL ) 01500 { 01501 if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) 01502 { 01503 /* The queue is a member of a queue set, and posting to 01504 the queue set caused a higher priority task to unblock. 01505 A context switch is required. */ 01506 vTaskMissedYield(); 01507 } 01508 } 01509 else 01510 { 01511 /* Tasks that are removed from the event list will get added to 01512 the pending ready list as the scheduler is still suspended. */ 01513 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01514 { 01515 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01516 { 01517 /* The task waiting has a higher priority so record that a 01518 context switch is required. */ 01519 vTaskMissedYield(); 01520 } 01521 } 01522 else 01523 { 01524 break; 01525 } 01526 } 01527 } 01528 #else /* configUSE_QUEUE_SETS */ 01529 { 01530 /* Tasks that are removed from the event list will get added to 01531 the pending ready list as the scheduler is still suspended. */ 01532 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01533 { 01534 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01535 { 01536 /* The task waiting has a higher priority so record that a 01537 context switch is required. */ 01538 vTaskMissedYield(); 01539 } 01540 } 01541 else 01542 { 01543 break; 01544 } 01545 } 01546 #endif /* configUSE_QUEUE_SETS */ 01547 01548 --( pxQueue->xTxLock ); 01549 } 01550 01551 pxQueue->xTxLock = queueUNLOCKED; 01552 } 01553 taskEXIT_CRITICAL(); 01554 01555 /* Do the same for the Rx lock. */ 01556 taskENTER_CRITICAL(); 01557 { 01558 while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) 01559 { 01560 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 01561 { 01562 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 01563 { 01564 vTaskMissedYield(); 01565 } 01566 01567 --( pxQueue->xRxLock ); 01568 } 01569 else 01570 { 01571 break; 01572 } 01573 } 01574 01575 pxQueue->xRxLock = queueUNLOCKED; 01576 } 01577 taskEXIT_CRITICAL(); 01578 } 01579 /*-----------------------------------------------------------*/ 01580 01581 static signed portBASE_TYPE prvIsQueueEmpty( const xQUEUE *pxQueue ) 01582 { 01583 signed portBASE_TYPE xReturn; 01584 01585 taskENTER_CRITICAL(); 01586 { 01587 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) 01588 { 01589 xReturn = pdTRUE; 01590 } 01591 else 01592 { 01593 xReturn = pdFALSE; 01594 } 01595 } 01596 taskEXIT_CRITICAL(); 01597 01598 return xReturn; 01599 } 01600 /*-----------------------------------------------------------*/ 01601 01602 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle xQueue ) 01603 { 01604 signed portBASE_TYPE xReturn; 01605 01606 configASSERT( xQueue ); 01607 if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) 01608 { 01609 xReturn = pdTRUE; 01610 } 01611 else 01612 { 01613 xReturn = pdFALSE; 01614 } 01615 01616 return xReturn; 01617 } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ 01618 /*-----------------------------------------------------------*/ 01619 01620 static signed portBASE_TYPE prvIsQueueFull( const xQUEUE *pxQueue ) 01621 { 01622 signed portBASE_TYPE xReturn; 01623 01624 taskENTER_CRITICAL(); 01625 { 01626 if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) 01627 { 01628 xReturn = pdTRUE; 01629 } 01630 else 01631 { 01632 xReturn = pdFALSE; 01633 } 01634 } 01635 taskEXIT_CRITICAL(); 01636 01637 return xReturn; 01638 } 01639 /*-----------------------------------------------------------*/ 01640 01641 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle xQueue ) 01642 { 01643 signed portBASE_TYPE xReturn; 01644 01645 configASSERT( xQueue ); 01646 if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == ( ( xQUEUE * ) xQueue )->uxLength ) 01647 { 01648 xReturn = pdTRUE; 01649 } 01650 else 01651 { 01652 xReturn = pdFALSE; 01653 } 01654 01655 return xReturn; 01656 } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ 01657 /*-----------------------------------------------------------*/ 01658 01659 #if ( configUSE_CO_ROUTINES == 1 ) 01660 01661 signed portBASE_TYPE xQueueCRSend( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait ) 01662 { 01663 signed portBASE_TYPE xReturn; 01664 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01665 01666 /* If the queue is already full we may have to block. A critical section 01667 is required to prevent an interrupt removing something from the queue 01668 between the check to see if the queue is full and blocking on the queue. */ 01669 portDISABLE_INTERRUPTS(); 01670 { 01671 if( prvIsQueueFull( pxQueue ) != pdFALSE ) 01672 { 01673 /* The queue is full - do we want to block or just leave without 01674 posting? */ 01675 if( xTicksToWait > ( portTickType ) 0 ) 01676 { 01677 /* As this is called from a coroutine we cannot block directly, but 01678 return indicating that we need to block. */ 01679 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); 01680 portENABLE_INTERRUPTS(); 01681 return errQUEUE_BLOCKED; 01682 } 01683 else 01684 { 01685 portENABLE_INTERRUPTS(); 01686 return errQUEUE_FULL; 01687 } 01688 } 01689 } 01690 portENABLE_INTERRUPTS(); 01691 01692 portDISABLE_INTERRUPTS(); 01693 { 01694 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) 01695 { 01696 /* There is room in the queue, copy the data into the queue. */ 01697 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); 01698 xReturn = pdPASS; 01699 01700 /* Were any co-routines waiting for data to become available? */ 01701 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01702 { 01703 /* In this instance the co-routine could be placed directly 01704 into the ready list as we are within a critical section. 01705 Instead the same pending ready list mechanism is used as if 01706 the event were caused from within an interrupt. */ 01707 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01708 { 01709 /* The co-routine waiting has a higher priority so record 01710 that a yield might be appropriate. */ 01711 xReturn = errQUEUE_YIELD; 01712 } 01713 } 01714 } 01715 else 01716 { 01717 xReturn = errQUEUE_FULL; 01718 } 01719 } 01720 portENABLE_INTERRUPTS(); 01721 01722 return xReturn; 01723 } 01724 01725 #endif /* configUSE_CO_ROUTINES */ 01726 /*-----------------------------------------------------------*/ 01727 01728 #if ( configUSE_CO_ROUTINES == 1 ) 01729 01730 signed portBASE_TYPE xQueueCRReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait ) 01731 { 01732 signed portBASE_TYPE xReturn; 01733 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01734 01735 /* If the queue is already empty we may have to block. A critical section 01736 is required to prevent an interrupt adding something to the queue 01737 between the check to see if the queue is empty and blocking on the queue. */ 01738 portDISABLE_INTERRUPTS(); 01739 { 01740 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) 01741 { 01742 /* There are no messages in the queue, do we want to block or just 01743 leave with nothing? */ 01744 if( xTicksToWait > ( portTickType ) 0 ) 01745 { 01746 /* As this is a co-routine we cannot block directly, but return 01747 indicating that we need to block. */ 01748 vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); 01749 portENABLE_INTERRUPTS(); 01750 return errQUEUE_BLOCKED; 01751 } 01752 else 01753 { 01754 portENABLE_INTERRUPTS(); 01755 return errQUEUE_FULL; 01756 } 01757 } 01758 } 01759 portENABLE_INTERRUPTS(); 01760 01761 portDISABLE_INTERRUPTS(); 01762 { 01763 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01764 { 01765 /* Data is available from the queue. */ 01766 pxQueue->u.pcReadFrom += pxQueue->uxItemSize; 01767 if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) 01768 { 01769 pxQueue->u.pcReadFrom = pxQueue->pcHead; 01770 } 01771 --( pxQueue->uxMessagesWaiting ); 01772 ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); 01773 01774 xReturn = pdPASS; 01775 01776 /* Were any co-routines waiting for space to become available? */ 01777 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 01778 { 01779 /* In this instance the co-routine could be placed directly 01780 into the ready list as we are within a critical section. 01781 Instead the same pending ready list mechanism is used as if 01782 the event were caused from within an interrupt. */ 01783 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 01784 { 01785 xReturn = errQUEUE_YIELD; 01786 } 01787 } 01788 } 01789 else 01790 { 01791 xReturn = pdFAIL; 01792 } 01793 } 01794 portENABLE_INTERRUPTS(); 01795 01796 return xReturn; 01797 } 01798 01799 #endif /* configUSE_CO_ROUTINES */ 01800 /*-----------------------------------------------------------*/ 01801 01802 #if ( configUSE_CO_ROUTINES == 1 ) 01803 01804 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle xQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) 01805 { 01806 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01807 01808 /* Cannot block within an ISR so if there is no space on the queue then 01809 exit without doing anything. */ 01810 if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) 01811 { 01812 prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); 01813 01814 /* We only want to wake one co-routine per ISR, so check that a 01815 co-routine has not already been woken. */ 01816 if( xCoRoutinePreviouslyWoken == pdFALSE ) 01817 { 01818 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 01819 { 01820 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 01821 { 01822 return pdTRUE; 01823 } 01824 } 01825 } 01826 } 01827 01828 return xCoRoutinePreviouslyWoken; 01829 } 01830 01831 #endif /* configUSE_CO_ROUTINES */ 01832 /*-----------------------------------------------------------*/ 01833 01834 #if ( configUSE_CO_ROUTINES == 1 ) 01835 01836 signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle xQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken ) 01837 { 01838 signed portBASE_TYPE xReturn; 01839 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01840 01841 /* We cannot block from an ISR, so check there is data available. If 01842 not then just leave without doing anything. */ 01843 if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) 01844 { 01845 /* Copy the data from the queue. */ 01846 pxQueue->u.pcReadFrom += pxQueue->uxItemSize; 01847 if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) 01848 { 01849 pxQueue->u.pcReadFrom = pxQueue->pcHead; 01850 } 01851 --( pxQueue->uxMessagesWaiting ); 01852 ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); 01853 01854 if( ( *pxCoRoutineWoken ) == pdFALSE ) 01855 { 01856 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 01857 { 01858 if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 01859 { 01860 *pxCoRoutineWoken = pdTRUE; 01861 } 01862 } 01863 } 01864 01865 xReturn = pdPASS; 01866 } 01867 else 01868 { 01869 xReturn = pdFAIL; 01870 } 01871 01872 return xReturn; 01873 } 01874 01875 #endif /* configUSE_CO_ROUTINES */ 01876 /*-----------------------------------------------------------*/ 01877 01878 #if ( configQUEUE_REGISTRY_SIZE > 0 ) 01879 01880 void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) 01881 { 01882 unsigned portBASE_TYPE ux; 01883 01884 /* See if there is an empty space in the registry. A NULL name denotes 01885 a free slot. */ 01886 for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) 01887 { 01888 if( xQueueRegistry[ ux ].pcQueueName == NULL ) 01889 { 01890 /* Store the information on this queue. */ 01891 xQueueRegistry[ ux ].pcQueueName = pcQueueName; 01892 xQueueRegistry[ ux ].xHandle = xQueue; 01893 break; 01894 } 01895 } 01896 } 01897 01898 #endif /* configQUEUE_REGISTRY_SIZE */ 01899 /*-----------------------------------------------------------*/ 01900 01901 #if ( configQUEUE_REGISTRY_SIZE > 0 ) 01902 01903 void vQueueUnregisterQueue( xQueueHandle xQueue ) 01904 { 01905 unsigned portBASE_TYPE ux; 01906 01907 /* See if the handle of the queue being unregistered in actually in the 01908 registry. */ 01909 for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) 01910 { 01911 if( xQueueRegistry[ ux ].xHandle == xQueue ) 01912 { 01913 /* Set the name to NULL to show that this slot if free again. */ 01914 xQueueRegistry[ ux ].pcQueueName = NULL; 01915 break; 01916 } 01917 } 01918 01919 } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ 01920 01921 #endif /* configQUEUE_REGISTRY_SIZE */ 01922 /*-----------------------------------------------------------*/ 01923 01924 #if ( configUSE_TIMERS == 1 ) 01925 01926 void vQueueWaitForMessageRestricted( xQueueHandle xQueue, portTickType xTicksToWait ) 01927 { 01928 xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; 01929 01930 /* This function should not be called by application code hence the 01931 'Restricted' in its name. It is not part of the public API. It is 01932 designed for use by kernel code, and has special calling requirements. 01933 It can result in vListInsert() being called on a list that can only 01934 possibly ever have one item in it, so the list will be fast, but even 01935 so it should be called with the scheduler locked and not from a critical 01936 section. */ 01937 01938 /* Only do anything if there are no messages in the queue. This function 01939 will not actually cause the task to block, just place it on a blocked 01940 list. It will not block until the scheduler is unlocked - at which 01941 time a yield will be performed. If an item is added to the queue while 01942 the queue is locked, and the calling task blocks on the queue, then the 01943 calling task will be immediately unblocked when the queue is unlocked. */ 01944 prvLockQueue( pxQueue ); 01945 if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U ) 01946 { 01947 /* There is nothing in the queue, block for the specified period. */ 01948 vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); 01949 } 01950 prvUnlockQueue( pxQueue ); 01951 } 01952 01953 #endif /* configUSE_TIMERS */ 01954 /*-----------------------------------------------------------*/ 01955 01956 #if ( configUSE_QUEUE_SETS == 1 ) 01957 01958 xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) 01959 { 01960 xQueueSetHandle pxQueue; 01961 01962 pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( xQUEUE * ), queueQUEUE_TYPE_SET ); 01963 01964 return pxQueue; 01965 } 01966 01967 #endif /* configUSE_QUEUE_SETS */ 01968 /*-----------------------------------------------------------*/ 01969 01970 #if ( configUSE_QUEUE_SETS == 1 ) 01971 01972 portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) 01973 { 01974 portBASE_TYPE xReturn; 01975 01976 if( ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) 01977 { 01978 /* Cannot add a queue/semaphore to more than one queue set. */ 01979 xReturn = pdFAIL; 01980 } 01981 else if( ( ( xQUEUE * ) xQueueOrSemaphore )->uxMessagesWaiting != ( unsigned portBASE_TYPE ) 0 ) 01982 { 01983 /* Cannot add a queue/semaphore to a queue set if there are already 01984 items in the queue/semaphore. */ 01985 xReturn = pdFAIL; 01986 } 01987 else 01988 { 01989 taskENTER_CRITICAL(); 01990 { 01991 ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet; 01992 } 01993 taskEXIT_CRITICAL(); 01994 xReturn = pdPASS; 01995 } 01996 01997 return xReturn; 01998 } 01999 02000 #endif /* configUSE_QUEUE_SETS */ 02001 /*-----------------------------------------------------------*/ 02002 02003 #if ( configUSE_QUEUE_SETS == 1 ) 02004 02005 portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) 02006 { 02007 portBASE_TYPE xReturn; 02008 xQUEUE * const pxQueueOrSemaphore = ( xQUEUE * ) xQueueOrSemaphore; 02009 02010 if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) 02011 { 02012 /* The queue was not a member of the set. */ 02013 xReturn = pdFAIL; 02014 } 02015 else if( pxQueueOrSemaphore->uxMessagesWaiting != ( unsigned portBASE_TYPE ) 0 ) 02016 { 02017 /* It is dangerous to remove a queue from a set when the queue is 02018 not empty because the queue set will still hold pending events for 02019 the queue. */ 02020 xReturn = pdFAIL; 02021 } 02022 else 02023 { 02024 taskENTER_CRITICAL(); 02025 { 02026 /* The queue is no longer contained in the set. */ 02027 pxQueueOrSemaphore->pxQueueSetContainer = NULL; 02028 } 02029 taskEXIT_CRITICAL(); 02030 xReturn = pdPASS; 02031 } 02032 02033 return xReturn; 02034 } /*lint !e818 xQueueSet could not be declared as pointing to const as it is a typedef. */ 02035 02036 #endif /* configUSE_QUEUE_SETS */ 02037 /*-----------------------------------------------------------*/ 02038 02039 #if ( configUSE_QUEUE_SETS == 1 ) 02040 02041 xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) 02042 { 02043 xQueueSetMemberHandle xReturn = NULL; 02044 02045 ( void ) xQueueGenericReceive( ( xQueueHandle ) xQueueSet, &xReturn, xBlockTimeTicks, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ 02046 return xReturn; 02047 } 02048 02049 #endif /* configUSE_QUEUE_SETS */ 02050 /*-----------------------------------------------------------*/ 02051 02052 #if ( configUSE_QUEUE_SETS == 1 ) 02053 02054 xQueueSetMemberHandle xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet ) 02055 { 02056 xQueueSetMemberHandle xReturn = NULL; 02057 02058 ( void ) xQueueReceiveFromISR( ( xQueueHandle ) xQueueSet, &xReturn, NULL ); /*lint !e961 Casting from one typedef to another is not redundant. */ 02059 return xReturn; 02060 } 02061 02062 #endif /* configUSE_QUEUE_SETS */ 02063 /*-----------------------------------------------------------*/ 02064 02065 #if ( configUSE_QUEUE_SETS == 1 ) 02066 02067 static portBASE_TYPE prvNotifyQueueSetContainer( const xQUEUE * const pxQueue, portBASE_TYPE xCopyPosition ) 02068 { 02069 xQUEUE *pxQueueSetContainer = pxQueue->pxQueueSetContainer; 02070 portBASE_TYPE xReturn = pdFALSE; 02071 02072 configASSERT( pxQueueSetContainer ); 02073 configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); 02074 02075 if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) 02076 { 02077 traceQUEUE_SEND( pxQueueSetContainer ); 02078 /* The data copies is the handle of the queue that contains data. */ 02079 prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); 02080 if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) 02081 { 02082 if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) 02083 { 02084 /* The task waiting has a higher priority */ 02085 xReturn = pdTRUE; 02086 } 02087 } 02088 } 02089 02090 return xReturn; 02091 } 02092 02093 #endif /* configUSE_QUEUE_SETS */ 02094 02095 02096 02097 02098 02099 02100 02101 02102 02103 02104 02105
Generated on Tue Jul 12 2022 11:36:40 by
1.7.2