1687 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			1687 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |     FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. | ||
|  | 
 | ||
|  |     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT  | ||
|  |     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
 | ||
|  | 
 | ||
|  |     *************************************************************************** | ||
|  |      *                                                                       * | ||
|  |      *    FreeRTOS tutorial books are available in pdf and paperback.        * | ||
|  |      *    Complete, revised, and edited pdf reference manuals are also       * | ||
|  |      *    available.                                                         * | ||
|  |      *                                                                       * | ||
|  |      *    Purchasing FreeRTOS documentation will not only help you, by       * | ||
|  |      *    ensuring you get running as quickly as possible and with an        * | ||
|  |      *    in-depth knowledge of how to use FreeRTOS, it will also help       * | ||
|  |      *    the FreeRTOS project to continue with its mission of providing     * | ||
|  |      *    professional grade, cross platform, de facto standard solutions    * | ||
|  |      *    for microcontrollers - completely free of charge!                  * | ||
|  |      *                                                                       * | ||
|  |      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
 | ||
|  |      *                                                                       * | ||
|  |      *    Thank you for using FreeRTOS, and thank you for your support!      * | ||
|  |      *                                                                       * | ||
|  |     *************************************************************************** | ||
|  | 
 | ||
|  | 
 | ||
|  |     This file is part of the FreeRTOS distribution. | ||
|  | 
 | ||
|  |     FreeRTOS is free software; you can redistribute it and/or modify it under | ||
|  |     the terms of the GNU General Public License (version 2) as published by the | ||
|  |     Free Software Foundation AND MODIFIED BY the FreeRTOS exception. | ||
|  |     >>>NOTE<<< The modification to the GPL is included to allow you to | ||
|  |     distribute a combined work that includes FreeRTOS without being obliged to | ||
|  |     provide the source code for proprietary components outside of the FreeRTOS | ||
|  |     kernel.  FreeRTOS is distributed in the hope that it will be useful, but | ||
|  |     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
|  |     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||
|  |     more details. You should have received a copy of the GNU General Public | ||
|  |     License and the FreeRTOS license exception along with FreeRTOS; if not it | ||
|  |     can be viewed here: http://www.freertos.org/a00114.html and also obtained
 | ||
|  |     by writing to Richard Barry, contact details for whom are available on the | ||
|  |     FreeRTOS WEB site. | ||
|  | 
 | ||
|  |     1 tab == 4 spaces! | ||
|  |      | ||
|  |     *************************************************************************** | ||
|  |      *                                                                       * | ||
|  |      *    Having a problem?  Start by reading the FAQ "My application does   * | ||
|  |      *    not run, what could be wrong?"                                     * | ||
|  |      *                                                                       * | ||
|  |      *    http://www.FreeRTOS.org/FAQHelp.html                               *
 | ||
|  |      *                                                                       * | ||
|  |     *************************************************************************** | ||
|  | 
 | ||
|  |      | ||
|  |     http://www.FreeRTOS.org - Documentation, training, latest versions, license 
 | ||
|  |     and contact details.   | ||
|  |      | ||
|  |     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
 | ||
|  |     including FreeRTOS+Trace - an indispensable productivity tool. | ||
|  | 
 | ||
|  |     Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell  | ||
|  |     the code with commercial support, indemnification, and middleware, under  | ||
|  |     the OpenRTOS brand: http://www.OpenRTOS.com.  High Integrity Systems also
 | ||
|  |     provide a safety engineered and independently SIL3 certified version under  | ||
|  |     the SafeRTOS brand: http://www.SafeRTOS.com.
 | ||
|  | */ | ||
|  | 
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <string.h>
 | ||
|  | 
 | ||
|  | /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
 | ||
|  | all the API functions to use the MPU wrappers.  That should only be done when | ||
|  | task.h is included from an application file. */ | ||
|  | #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
 | ||
|  | 
 | ||
|  | #include "FreeRTOS.h"
 | ||
|  | #include "task.h"
 | ||
|  | 
 | ||
|  | #if ( configUSE_CO_ROUTINES == 1 )
 | ||
|  | 	#include "croutine.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
 | ||
|  | 
 | ||
|  | /*-----------------------------------------------------------
 | ||
|  |  * PUBLIC LIST API documented in list.h | ||
|  |  *----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /* Constants used with the cRxLock and xTxLock structure members. */ | ||
|  | #define queueUNLOCKED					( ( signed portBASE_TYPE ) -1 )
 | ||
|  | #define queueLOCKED_UNMODIFIED			( ( signed portBASE_TYPE ) 0 )
 | ||
|  | 
 | ||
|  | #define queueERRONEOUS_UNBLOCK			( -1 )
 | ||
|  | 
 | ||
|  | /* For internal use only. */ | ||
|  | #define	queueSEND_TO_BACK				( 0 )
 | ||
|  | #define	queueSEND_TO_FRONT				( 1 )
 | ||
|  | 
 | ||
|  | /* Effectively make a union out of the xQUEUE structure. */ | ||
|  | #define pxMutexHolder					pcTail
 | ||
|  | #define uxQueueType						pcHead
 | ||
|  | #define uxRecursiveCallCount			pcReadFrom
 | ||
|  | #define queueQUEUE_IS_MUTEX				NULL
 | ||
|  | 
 | ||
|  | /* Semaphores do not actually store or copy data, so have an items size of
 | ||
|  | zero. */ | ||
|  | #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portBASE_TYPE ) 0 )
 | ||
|  | #define queueDONT_BLOCK					 ( ( portTickType ) 0U )
 | ||
|  | #define queueMUTEX_GIVE_BLOCK_TIME		 ( ( portTickType ) 0U )
 | ||
|  | 
 | ||
|  | /* These definitions *must* match those in queue.h. */ | ||
|  | #define queueQUEUE_TYPE_BASE				( 0U )
 | ||
|  | #define queueQUEUE_TYPE_MUTEX 				( 1U )
 | ||
|  | #define queueQUEUE_TYPE_COUNTING_SEMAPHORE	( 2U )
 | ||
|  | #define queueQUEUE_TYPE_BINARY_SEMAPHORE	( 3U )
 | ||
|  | #define queueQUEUE_TYPE_RECURSIVE_MUTEX		( 4U )
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Definition of the queue used by the scheduler. | ||
|  |  * Items are queued by copy, not reference. | ||
|  |  */ | ||
|  | typedef struct QueueDefinition | ||
|  | { | ||
|  | 	signed char *pcHead;				/*< Points to the beginning of the queue storage area. */ | ||
|  | 	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. */ | ||
|  | 
 | ||
|  | 	signed char *pcWriteTo;				/*< Points to the free next place in the storage area. */ | ||
|  | 	signed char *pcReadFrom;			/*< Points to the last place that a queued item was read from. */ | ||
|  | 
 | ||
|  | 	xList xTasksWaitingToSend;				/*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */ | ||
|  | 	xList xTasksWaitingToReceive;			/*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */ | ||
|  | 
 | ||
|  | 	volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */ | ||
|  | 	unsigned portBASE_TYPE uxLength;		/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ | ||
|  | 	unsigned portBASE_TYPE uxItemSize;		/*< The size of each items that the queue will hold. */ | ||
|  | 
 | ||
|  | 	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. */ | ||
|  | 	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. */ | ||
|  | 
 | ||
|  | 	#if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 		unsigned char ucQueueNumber; | ||
|  | 		unsigned char ucQueueType; | ||
|  | 	#endif
 | ||
|  | 
 | ||
|  | } xQUEUE; | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Inside this file xQueueHandle is a pointer to a xQUEUE structure. | ||
|  |  * To keep the definition private the API header file defines it as a | ||
|  |  * pointer to void. | ||
|  |  */ | ||
|  | typedef xQUEUE * xQueueHandle; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Prototypes for public functions are included here so we don't have to | ||
|  |  * include the API header file (as it defines xQueueHandle differently).  These | ||
|  |  * functions are documented in the API header file. | ||
|  |  */ | ||
|  | xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; | ||
|  | unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; | ||
|  | xQueueHandle xQueueCreateMutex( unsigned char ucQueueType ) PRIVILEGED_FUNCTION; | ||
|  | xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION; | ||
|  | portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION; | ||
|  | portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; | ||
|  | unsigned char ucQueueGetQueueNumber( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber ) PRIVILEGED_FUNCTION; | ||
|  | unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) PRIVILEGED_FUNCTION; | ||
|  | xTaskHandle xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Co-routine queue functions differ from task queue functions.  Co-routines are | ||
|  |  * an optional component. | ||
|  |  */ | ||
|  | #if configUSE_CO_ROUTINES == 1
 | ||
|  | 	signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION; | ||
|  | 	signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION; | ||
|  | 	signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; | ||
|  | 	signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * The queue registry is just a means for kernel aware debuggers to locate | ||
|  |  * queue structures.  It has no other purpose so is an optional component. | ||
|  |  */ | ||
|  | #if configQUEUE_REGISTRY_SIZE > 0
 | ||
|  | 
 | ||
|  | 	/* The type stored within the queue registry array.  This allows a name
 | ||
|  | 	to be assigned to each queue making kernel aware debugging a little | ||
|  | 	more user friendly. */ | ||
|  | 	typedef struct QUEUE_REGISTRY_ITEM | ||
|  | 	{ | ||
|  | 		signed char *pcQueueName; | ||
|  | 		xQueueHandle xHandle; | ||
|  | 	} xQueueRegistryItem; | ||
|  | 
 | ||
|  | 	/* The queue registry is simply an array of xQueueRegistryItem structures.
 | ||
|  | 	The pcQueueName member of a structure being NULL is indicative of the | ||
|  | 	array position being vacant. */ | ||
|  | 	xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; | ||
|  | 
 | ||
|  | 	/* Removes a queue from the registry by simply setting the pcQueueName
 | ||
|  | 	member to NULL. */ | ||
|  | 	static void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; | ||
|  | 	void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) PRIVILEGED_FUNCTION; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not | ||
|  |  * prevent an ISR from adding or removing items to the queue, but does prevent | ||
|  |  * an ISR from removing tasks from the queue event lists.  If an ISR finds a | ||
|  |  * queue is locked it will instead increment the appropriate queue lock count | ||
|  |  * to indicate that a task may require unblocking.  When the queue in unlocked | ||
|  |  * these lock counts are inspected, and the appropriate action taken. | ||
|  |  */ | ||
|  | static void prvUnlockQueue( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Uses a critical section to determine if there is any data in a queue. | ||
|  |  * | ||
|  |  * @return pdTRUE if the queue contains no items, otherwise pdFALSE. | ||
|  |  */ | ||
|  | static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Uses a critical section to determine if there is any space in a queue. | ||
|  |  * | ||
|  |  * @return pdTRUE if there is no space, otherwise pdFALSE; | ||
|  |  */ | ||
|  | static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Copies an item into the queue, either at the front of the queue or the | ||
|  |  * back of the queue. | ||
|  |  */ | ||
|  | static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Copies an item out of a queue. | ||
|  |  */ | ||
|  | static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION; | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Macro to mark a queue as locked.  Locking a queue prevents an ISR from | ||
|  |  * accessing the queue event lists. | ||
|  |  */ | ||
|  | #define prvLockQueue( pxQueue )								\
 | ||
|  | 	taskENTER_CRITICAL();									\ | ||
|  | 	{														\ | ||
|  | 		if( ( pxQueue )->xRxLock == queueUNLOCKED )			\ | ||
|  | 		{													\ | ||
|  | 			( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED;	\ | ||
|  | 		}													\ | ||
|  | 		if( ( pxQueue )->xTxLock == queueUNLOCKED )			\ | ||
|  | 		{													\ | ||
|  | 			( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED;	\ | ||
|  | 		}													\ | ||
|  | 	}														\ | ||
|  | 	taskEXIT_CRITICAL() | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | 
 | ||
|  | /*-----------------------------------------------------------
 | ||
|  |  * PUBLIC QUEUE MANAGEMENT API documented in queue.h | ||
|  |  *----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) | ||
|  | { | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 
 | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 	{ | ||
|  | 		pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); | ||
|  | 		pxQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; | ||
|  | 		pxQueue->pcWriteTo = pxQueue->pcHead; | ||
|  | 		pxQueue->pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( unsigned portBASE_TYPE ) 1U ) * pxQueue->uxItemSize ); | ||
|  | 		pxQueue->xRxLock = queueUNLOCKED; | ||
|  | 		pxQueue->xTxLock = queueUNLOCKED; | ||
|  | 
 | ||
|  | 		if( xNewQueue == pdFALSE ) | ||
|  | 		{ | ||
|  | 			/* If there are tasks blocked waiting to read from the queue, then
 | ||
|  | 			the tasks will remain blocked as after this function exits the queue | ||
|  | 			will still be empty.  If there are tasks blocked waiting to	write to | ||
|  | 			the queue, then one should be unblocked as after this function exits | ||
|  | 			it will be possible to write to it. */ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) | ||
|  | 				{ | ||
|  | 					portYIELD_WITHIN_API(); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			/* Ensure the event queues start in the correct state. */ | ||
|  | 			vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); | ||
|  | 			vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); | ||
|  | 		} | ||
|  | 	} | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 	/* A value is returned for calling semantic consistency with previous
 | ||
|  | 	versions. */ | ||
|  | 	return pdPASS; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) | ||
|  | { | ||
|  | xQUEUE *pxNewQueue; | ||
|  | size_t xQueueSizeInBytes; | ||
|  | xQueueHandle xReturn = NULL; | ||
|  | 
 | ||
|  | 	/* Remove compiler warnings about unused parameters should
 | ||
|  | 	configUSE_TRACE_FACILITY not be set to 1. */ | ||
|  | 	( void ) ucQueueType; | ||
|  | 
 | ||
|  | 	/* Allocate the new queue structure. */ | ||
|  | 	if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 	{ | ||
|  | 		pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) ); | ||
|  | 		if( pxNewQueue != NULL ) | ||
|  | 		{ | ||
|  | 			/* Create the list of pointers to queue items.  The queue is one byte
 | ||
|  | 			longer than asked for to make wrap checking easier/faster. */ | ||
|  | 			xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; | ||
|  | 
 | ||
|  | 			pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes ); | ||
|  | 			if( pxNewQueue->pcHead != NULL ) | ||
|  | 			{ | ||
|  | 				/* Initialise the queue members as described above where the
 | ||
|  | 				queue type is defined. */ | ||
|  | 				pxNewQueue->uxLength = uxQueueLength; | ||
|  | 				pxNewQueue->uxItemSize = uxItemSize; | ||
|  | 				xQueueGenericReset( pxNewQueue, pdTRUE ); | ||
|  | 				#if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 				{ | ||
|  | 					pxNewQueue->ucQueueType = ucQueueType; | ||
|  | 				} | ||
|  | 				#endif /* configUSE_TRACE_FACILITY */
 | ||
|  | 
 | ||
|  | 				traceQUEUE_CREATE( pxNewQueue ); | ||
|  | 				xReturn = pxNewQueue; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				traceQUEUE_CREATE_FAILED( ucQueueType ); | ||
|  | 				vPortFree( pxNewQueue ); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	configASSERT( xReturn ); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( configUSE_MUTEXES == 1 )
 | ||
|  | 
 | ||
|  | 	xQueueHandle xQueueCreateMutex( unsigned char ucQueueType ) | ||
|  | 	{ | ||
|  | 	xQUEUE *pxNewQueue; | ||
|  | 
 | ||
|  | 		/* Prevent compiler warnings about unused parameters if
 | ||
|  | 		configUSE_TRACE_FACILITY does not equal 1. */ | ||
|  | 		( void ) ucQueueType; | ||
|  | 
 | ||
|  | 		/* Allocate the new queue structure. */ | ||
|  | 		pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) ); | ||
|  | 		if( pxNewQueue != NULL ) | ||
|  | 		{ | ||
|  | 			/* Information required for priority inheritance. */ | ||
|  | 			pxNewQueue->pxMutexHolder = NULL; | ||
|  | 			pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; | ||
|  | 
 | ||
|  | 			/* Queues used as a mutex no data is actually copied into or out
 | ||
|  | 			of the queue. */ | ||
|  | 			pxNewQueue->pcWriteTo = NULL; | ||
|  | 			pxNewQueue->pcReadFrom = NULL; | ||
|  | 
 | ||
|  | 			/* Each mutex has a length of 1 (like a binary semaphore) and
 | ||
|  | 			an item size of 0 as nothing is actually copied into or out | ||
|  | 			of the mutex. */ | ||
|  | 			pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; | ||
|  | 			pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U; | ||
|  | 			pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U; | ||
|  | 			pxNewQueue->xRxLock = queueUNLOCKED; | ||
|  | 			pxNewQueue->xTxLock = queueUNLOCKED; | ||
|  | 
 | ||
|  | 			#if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 			{ | ||
|  | 				pxNewQueue->ucQueueType = ucQueueType; | ||
|  | 			} | ||
|  | 			#endif
 | ||
|  | 
 | ||
|  | 			/* Ensure the event queues start with the correct state. */ | ||
|  | 			vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); | ||
|  | 			vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); | ||
|  | 
 | ||
|  | 			traceCREATE_MUTEX( pxNewQueue ); | ||
|  | 
 | ||
|  | 			/* Start with the semaphore in the expected state. */ | ||
|  | 			xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK ); | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			traceCREATE_MUTEX_FAILED(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		configASSERT( pxNewQueue ); | ||
|  | 		return pxNewQueue; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif /* configUSE_MUTEXES */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xQueueGetMutexHolder == 1 ) )
 | ||
|  | 
 | ||
|  | 	void* xQueueGetMutexHolder( xQueueHandle xSemaphore ) | ||
|  | 	{ | ||
|  | 	void *pxReturn; | ||
|  | 
 | ||
|  | 		/* This function is called by xSemaphoreGetMutexHolder(), and should not
 | ||
|  | 		be called directly.  Note:  This is is a good way of determining if the | ||
|  | 		calling task is the mutex holder, but not a good way of determining the | ||
|  | 		identity of the mutex holder, as the holder may change between the | ||
|  | 		following critical section exiting and the function returning. */ | ||
|  | 		taskENTER_CRITICAL(); | ||
|  | 		{ | ||
|  | 			if( xSemaphore->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 			{ | ||
|  | 				pxReturn = ( void * ) xSemaphore->pxMutexHolder; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				pxReturn = NULL; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 		return pxReturn; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( configUSE_RECURSIVE_MUTEXES == 1 )
 | ||
|  | 
 | ||
|  | 	portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex ) | ||
|  | 	{ | ||
|  | 	portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 		configASSERT( pxMutex ); | ||
|  | 
 | ||
|  | 		/* If this is the task that holds the mutex then pxMutexHolder will not
 | ||
|  | 		change outside of this task.  If this task does not hold the mutex then | ||
|  | 		pxMutexHolder can never coincidentally equal the tasks handle, and as | ||
|  | 		this is the only condition we are interested in it does not matter if | ||
|  | 		pxMutexHolder is accessed simultaneously by another task.  Therefore no | ||
|  | 		mutual exclusion is required to test the pxMutexHolder variable. */ | ||
|  | 		if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() ) | ||
|  | 		{ | ||
|  | 			traceGIVE_MUTEX_RECURSIVE( pxMutex ); | ||
|  | 
 | ||
|  | 			/* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
 | ||
|  | 			the task handle, therefore no underflow check is required.  Also, | ||
|  | 			uxRecursiveCallCount is only modified by the mutex holder, and as | ||
|  | 			there can only be one, no mutual exclusion is required to modify the | ||
|  | 			uxRecursiveCallCount member. */ | ||
|  | 			( pxMutex->uxRecursiveCallCount )--; | ||
|  | 
 | ||
|  | 			/* Have we unwound the call count? */ | ||
|  | 			if( pxMutex->uxRecursiveCallCount == 0 ) | ||
|  | 			{ | ||
|  | 				/* Return the mutex.  This will automatically unblock any other
 | ||
|  | 				task that might be waiting to access the mutex. */ | ||
|  | 				xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			xReturn = pdPASS; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			/* We cannot give the mutex because we are not the holder. */ | ||
|  | 			xReturn = pdFAIL; | ||
|  | 
 | ||
|  | 			traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return xReturn; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif /* configUSE_RECURSIVE_MUTEXES */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_RECURSIVE_MUTEXES == 1
 | ||
|  | 
 | ||
|  | 	portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime ) | ||
|  | 	{ | ||
|  | 	portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 		configASSERT( pxMutex ); | ||
|  | 
 | ||
|  | 		/* Comments regarding mutual exclusion as per those within
 | ||
|  | 		xQueueGiveMutexRecursive(). */ | ||
|  | 
 | ||
|  | 		traceTAKE_MUTEX_RECURSIVE( pxMutex ); | ||
|  | 
 | ||
|  | 		if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() ) | ||
|  | 		{ | ||
|  | 			( pxMutex->uxRecursiveCallCount )++; | ||
|  | 			xReturn = pdPASS; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE ); | ||
|  | 
 | ||
|  | 			/* pdPASS will only be returned if we successfully obtained the mutex,
 | ||
|  | 			we may have blocked to reach here. */ | ||
|  | 			if( xReturn == pdPASS ) | ||
|  | 			{ | ||
|  | 				( pxMutex->uxRecursiveCallCount )++; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return xReturn; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif /* configUSE_RECURSIVE_MUTEXES */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_COUNTING_SEMAPHORES == 1
 | ||
|  | 
 | ||
|  | 	xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) | ||
|  | 	{ | ||
|  | 	xQueueHandle pxHandle; | ||
|  | 
 | ||
|  | 		pxHandle = xQueueGenericCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); | ||
|  | 
 | ||
|  | 		if( pxHandle != NULL ) | ||
|  | 		{ | ||
|  | 			pxHandle->uxMessagesWaiting = uxInitialCount; | ||
|  | 
 | ||
|  | 			traceCREATE_COUNTING_SEMAPHORE(); | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			traceCREATE_COUNTING_SEMAPHORE_FAILED(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		configASSERT( pxHandle ); | ||
|  | 		return pxHandle; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif /* configUSE_COUNTING_SEMAPHORES */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) | ||
|  | { | ||
|  | signed portBASE_TYPE xEntryTimeSet = pdFALSE; | ||
|  | xTimeOutType xTimeOut; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 	/* This function relaxes the coding standard somewhat to allow return
 | ||
|  | 	statements within the function itself.  This is done in the interest | ||
|  | 	of execution time efficiency. */ | ||
|  | 	for( ;; ) | ||
|  | 	{ | ||
|  | 		taskENTER_CRITICAL(); | ||
|  | 		{ | ||
|  | 			/* Is there room on the queue now?  To be running we must be
 | ||
|  | 			the highest priority task wanting to access the queue. */ | ||
|  | 			if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) | ||
|  | 			{ | ||
|  | 				traceQUEUE_SEND( pxQueue ); | ||
|  | 				prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); | ||
|  | 
 | ||
|  | 				/* If there was a task waiting for data to arrive on the
 | ||
|  | 				queue then unblock it now. */ | ||
|  | 				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 				{ | ||
|  | 					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) | ||
|  | 					{ | ||
|  | 						/* The unblocked task has a priority higher than
 | ||
|  | 						our own so yield immediately.  Yes it is ok to do | ||
|  | 						this from within the critical section - the kernel | ||
|  | 						takes care of that. */ | ||
|  | 						portYIELD_WITHIN_API(); | ||
|  | 					} | ||
|  | 				} | ||
|  | 
 | ||
|  | 				taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 				/* Return to the original privilege level before exiting the
 | ||
|  | 				function. */ | ||
|  | 				return pdPASS; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				if( xTicksToWait == ( portTickType ) 0 ) | ||
|  | 				{ | ||
|  | 					/* The queue was full and no block time is specified (or
 | ||
|  | 					the block time has expired) so leave now. */ | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 					/* Return to the original privilege level before exiting
 | ||
|  | 					the function. */ | ||
|  | 					traceQUEUE_SEND_FAILED( pxQueue ); | ||
|  | 					return errQUEUE_FULL; | ||
|  | 				} | ||
|  | 				else if( xEntryTimeSet == pdFALSE ) | ||
|  | 				{ | ||
|  | 					/* The queue was full and a block time was specified so
 | ||
|  | 					configure the timeout structure. */ | ||
|  | 					vTaskSetTimeOutState( &xTimeOut ); | ||
|  | 					xEntryTimeSet = pdTRUE; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 		/* Interrupts and other tasks can send to and receive from the queue
 | ||
|  | 		now the critical section has been exited. */ | ||
|  | 
 | ||
|  | 		vTaskSuspendAll(); | ||
|  | 		prvLockQueue( pxQueue ); | ||
|  | 
 | ||
|  | 		/* Update the timeout state to see if it has expired yet. */ | ||
|  | 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) | ||
|  | 		{ | ||
|  | 			if( prvIsQueueFull( pxQueue ) != pdFALSE ) | ||
|  | 			{ | ||
|  | 				traceBLOCKING_ON_QUEUE_SEND( pxQueue ); | ||
|  | 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); | ||
|  | 
 | ||
|  | 				/* Unlocking the queue means queue events can effect the
 | ||
|  | 				event list.  It is possible	that interrupts occurring now | ||
|  | 				remove this task from the event	list again - but as the | ||
|  | 				scheduler is suspended the task will go onto the pending | ||
|  | 				ready last instead of the actual ready list. */ | ||
|  | 				prvUnlockQueue( pxQueue ); | ||
|  | 
 | ||
|  | 				/* Resuming the scheduler will move tasks from the pending
 | ||
|  | 				ready list into the ready list - so it is feasible that this | ||
|  | 				task is already in a ready list before it yields - in which | ||
|  | 				case the yield will not cause a context switch unless there | ||
|  | 				is also a higher priority task in the pending ready list. */ | ||
|  | 				if( xTaskResumeAll() == pdFALSE ) | ||
|  | 				{ | ||
|  | 					portYIELD_WITHIN_API(); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				/* Try again. */ | ||
|  | 				prvUnlockQueue( pxQueue ); | ||
|  | 				( void ) xTaskResumeAll(); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			/* The timeout has expired. */ | ||
|  | 			prvUnlockQueue( pxQueue ); | ||
|  | 			( void ) xTaskResumeAll(); | ||
|  | 
 | ||
|  | 			/* Return to the original privilege level before exiting the
 | ||
|  | 			function. */ | ||
|  | 			traceQUEUE_SEND_FAILED( pxQueue ); | ||
|  | 			return errQUEUE_FULL; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_ALTERNATIVE_API == 1
 | ||
|  | 
 | ||
|  | 	signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) | ||
|  | 	{ | ||
|  | 	signed portBASE_TYPE xEntryTimeSet = pdFALSE; | ||
|  | 	xTimeOutType xTimeOut; | ||
|  | 
 | ||
|  | 		configASSERT( pxQueue ); | ||
|  | 		configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 		for( ;; ) | ||
|  | 		{ | ||
|  | 			taskENTER_CRITICAL(); | ||
|  | 			{ | ||
|  | 				/* Is there room on the queue now?  To be running we must be
 | ||
|  | 				the highest priority task wanting to access the queue. */ | ||
|  | 				if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) | ||
|  | 				{ | ||
|  | 					traceQUEUE_SEND( pxQueue ); | ||
|  | 					prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); | ||
|  | 
 | ||
|  | 					/* If there was a task waiting for data to arrive on the
 | ||
|  | 					queue then unblock it now. */ | ||
|  | 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 					{ | ||
|  | 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) | ||
|  | 						{ | ||
|  | 							/* The unblocked task has a priority higher than
 | ||
|  | 							our own so yield immediately. */ | ||
|  | 							portYIELD_WITHIN_API(); | ||
|  | 						} | ||
|  | 					} | ||
|  | 
 | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 					return pdPASS; | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					if( xTicksToWait == ( portTickType ) 0 ) | ||
|  | 					{ | ||
|  | 						taskEXIT_CRITICAL(); | ||
|  | 						return errQUEUE_FULL; | ||
|  | 					} | ||
|  | 					else if( xEntryTimeSet == pdFALSE ) | ||
|  | 					{ | ||
|  | 						vTaskSetTimeOutState( &xTimeOut ); | ||
|  | 						xEntryTimeSet = pdTRUE; | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 			taskENTER_CRITICAL(); | ||
|  | 			{ | ||
|  | 				if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) | ||
|  | 				{ | ||
|  | 					if( prvIsQueueFull( pxQueue ) != pdFALSE ) | ||
|  | 					{ | ||
|  | 						traceBLOCKING_ON_QUEUE_SEND( pxQueue ); | ||
|  | 						vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); | ||
|  | 						portYIELD_WITHIN_API(); | ||
|  | 					} | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 					traceQUEUE_SEND_FAILED( pxQueue ); | ||
|  | 					return errQUEUE_FULL; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			taskEXIT_CRITICAL(); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif /* configUSE_ALTERNATIVE_API */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_ALTERNATIVE_API == 1
 | ||
|  | 
 | ||
|  | 	signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) | ||
|  | 	{ | ||
|  | 	signed portBASE_TYPE xEntryTimeSet = pdFALSE; | ||
|  | 	xTimeOutType xTimeOut; | ||
|  | 	signed char *pcOriginalReadPosition; | ||
|  | 
 | ||
|  | 		configASSERT( pxQueue ); | ||
|  | 		configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 		for( ;; ) | ||
|  | 		{ | ||
|  | 			taskENTER_CRITICAL(); | ||
|  | 			{ | ||
|  | 				if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 				{ | ||
|  | 					/* Remember our read position in case we are just peeking. */ | ||
|  | 					pcOriginalReadPosition = pxQueue->pcReadFrom; | ||
|  | 
 | ||
|  | 					prvCopyDataFromQueue( pxQueue, pvBuffer ); | ||
|  | 
 | ||
|  | 					if( xJustPeeking == pdFALSE ) | ||
|  | 					{ | ||
|  | 						traceQUEUE_RECEIVE( pxQueue ); | ||
|  | 
 | ||
|  | 						/* We are actually removing data. */ | ||
|  | 						--( pxQueue->uxMessagesWaiting ); | ||
|  | 
 | ||
|  | 						#if ( configUSE_MUTEXES == 1 )
 | ||
|  | 						{ | ||
|  | 							if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 							{ | ||
|  | 								/* Record the information required to implement
 | ||
|  | 								priority inheritance should it become necessary. */ | ||
|  | 								pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); | ||
|  | 							} | ||
|  | 						} | ||
|  | 						#endif
 | ||
|  | 
 | ||
|  | 						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 						{ | ||
|  | 							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) | ||
|  | 							{ | ||
|  | 								portYIELD_WITHIN_API(); | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} | ||
|  | 					else | ||
|  | 					{ | ||
|  | 						traceQUEUE_PEEK( pxQueue ); | ||
|  | 
 | ||
|  | 						/* We are not removing the data, so reset our read
 | ||
|  | 						pointer. */ | ||
|  | 						pxQueue->pcReadFrom = pcOriginalReadPosition; | ||
|  | 
 | ||
|  | 						/* The data is being left in the queue, so see if there are
 | ||
|  | 						any other tasks waiting for the data. */ | ||
|  | 						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 						{ | ||
|  | 							/* Tasks that are removed from the event list will get added to
 | ||
|  | 							the pending ready list as the scheduler is still suspended. */ | ||
|  | 							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 							{ | ||
|  | 								/* The task waiting has a higher priority than this task. */ | ||
|  | 								portYIELD_WITHIN_API(); | ||
|  | 							} | ||
|  | 						} | ||
|  | 
 | ||
|  | 					} | ||
|  | 
 | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 					return pdPASS; | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					if( xTicksToWait == ( portTickType ) 0 ) | ||
|  | 					{ | ||
|  | 						taskEXIT_CRITICAL(); | ||
|  | 						traceQUEUE_RECEIVE_FAILED( pxQueue ); | ||
|  | 						return errQUEUE_EMPTY; | ||
|  | 					} | ||
|  | 					else if( xEntryTimeSet == pdFALSE ) | ||
|  | 					{ | ||
|  | 						vTaskSetTimeOutState( &xTimeOut ); | ||
|  | 						xEntryTimeSet = pdTRUE; | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 			taskENTER_CRITICAL(); | ||
|  | 			{ | ||
|  | 				if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) | ||
|  | 				{ | ||
|  | 					if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) | ||
|  | 					{ | ||
|  | 						traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); | ||
|  | 
 | ||
|  | 						#if ( configUSE_MUTEXES == 1 )
 | ||
|  | 						{ | ||
|  | 							if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 							{ | ||
|  | 								portENTER_CRITICAL(); | ||
|  | 								{ | ||
|  | 									vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); | ||
|  | 								} | ||
|  | 								portEXIT_CRITICAL(); | ||
|  | 							} | ||
|  | 						} | ||
|  | 						#endif
 | ||
|  | 
 | ||
|  | 						vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); | ||
|  | 						portYIELD_WITHIN_API(); | ||
|  | 					} | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 					traceQUEUE_RECEIVE_FAILED( pxQueue ); | ||
|  | 					return errQUEUE_EMPTY; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			taskEXIT_CRITICAL(); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif /* configUSE_ALTERNATIVE_API */
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | unsigned portBASE_TYPE uxSavedInterruptStatus; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 	/* Similar to xQueueGenericSend, except we don't block if there is no room
 | ||
|  | 	in the queue.  Also we don't directly wake a task that was blocked on a | ||
|  | 	queue read, instead we return a flag to say whether a context switch is | ||
|  | 	required or not (i.e. has a task with a higher priority than us been woken | ||
|  | 	by this	post). */ | ||
|  | 	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); | ||
|  | 	{ | ||
|  | 		if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) | ||
|  | 		{ | ||
|  | 			traceQUEUE_SEND_FROM_ISR( pxQueue ); | ||
|  | 
 | ||
|  | 			prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); | ||
|  | 
 | ||
|  | 			/* If the queue is locked we do not alter the event list.  This will
 | ||
|  | 			be done when the queue is unlocked later. */ | ||
|  | 			if( pxQueue->xTxLock == queueUNLOCKED ) | ||
|  | 			{ | ||
|  | 				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 				{ | ||
|  | 					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 					{ | ||
|  | 						/* The task waiting has a higher priority so record that a
 | ||
|  | 						context	switch is required. */ | ||
|  | 						if( pxHigherPriorityTaskWoken != NULL ) | ||
|  | 						{ | ||
|  | 							*pxHigherPriorityTaskWoken = pdTRUE; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				/* Increment the lock count so the task that unlocks the queue
 | ||
|  | 				knows that data was posted while it was locked. */ | ||
|  | 				++( pxQueue->xTxLock ); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			xReturn = pdPASS; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); | ||
|  | 			xReturn = errQUEUE_FULL; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) | ||
|  | { | ||
|  | signed portBASE_TYPE xEntryTimeSet = pdFALSE; | ||
|  | xTimeOutType xTimeOut; | ||
|  | signed char *pcOriginalReadPosition; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 	/* This function relaxes the coding standard somewhat to allow return
 | ||
|  | 	statements within the function itself.  This is done in the interest | ||
|  | 	of execution time efficiency. */ | ||
|  | 
 | ||
|  | 	for( ;; ) | ||
|  | 	{ | ||
|  | 		taskENTER_CRITICAL(); | ||
|  | 		{ | ||
|  | 			/* Is there data in the queue now?  To be running we must be
 | ||
|  | 			the highest priority task wanting to access the queue. */ | ||
|  | 			if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 			{ | ||
|  | 				/* Remember our read position in case we are just peeking. */ | ||
|  | 				pcOriginalReadPosition = pxQueue->pcReadFrom; | ||
|  | 
 | ||
|  | 				prvCopyDataFromQueue( pxQueue, pvBuffer ); | ||
|  | 
 | ||
|  | 				if( xJustPeeking == pdFALSE ) | ||
|  | 				{ | ||
|  | 					traceQUEUE_RECEIVE( pxQueue ); | ||
|  | 
 | ||
|  | 					/* We are actually removing data. */ | ||
|  | 					--( pxQueue->uxMessagesWaiting ); | ||
|  | 
 | ||
|  | 					#if ( configUSE_MUTEXES == 1 )
 | ||
|  | 					{ | ||
|  | 						if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 						{ | ||
|  | 							/* Record the information required to implement
 | ||
|  | 							priority inheritance should it become necessary. */ | ||
|  | 							pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); | ||
|  | 						} | ||
|  | 					} | ||
|  | 					#endif
 | ||
|  | 
 | ||
|  | 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 					{ | ||
|  | 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) | ||
|  | 						{ | ||
|  | 							portYIELD_WITHIN_API(); | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					traceQUEUE_PEEK( pxQueue ); | ||
|  | 
 | ||
|  | 					/* We are not removing the data, so reset our read
 | ||
|  | 					pointer. */ | ||
|  | 					pxQueue->pcReadFrom = pcOriginalReadPosition; | ||
|  | 
 | ||
|  | 					/* The data is being left in the queue, so see if there are
 | ||
|  | 					any other tasks waiting for the data. */ | ||
|  | 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 					{ | ||
|  | 						/* Tasks that are removed from the event list will get added to
 | ||
|  | 						the pending ready list as the scheduler is still suspended. */ | ||
|  | 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 						{ | ||
|  | 							/* The task waiting has a higher priority than this task. */ | ||
|  | 							portYIELD_WITHIN_API(); | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 
 | ||
|  | 				taskEXIT_CRITICAL(); | ||
|  | 				return pdPASS; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				if( xTicksToWait == ( portTickType ) 0 ) | ||
|  | 				{ | ||
|  | 					/* The queue was empty and no block time is specified (or
 | ||
|  | 					the block time has expired) so leave now. */ | ||
|  | 					taskEXIT_CRITICAL(); | ||
|  | 					traceQUEUE_RECEIVE_FAILED( pxQueue ); | ||
|  | 					return errQUEUE_EMPTY; | ||
|  | 				} | ||
|  | 				else if( xEntryTimeSet == pdFALSE ) | ||
|  | 				{ | ||
|  | 					/* The queue was empty and a block time was specified so
 | ||
|  | 					configure the timeout structure. */ | ||
|  | 					vTaskSetTimeOutState( &xTimeOut ); | ||
|  | 					xEntryTimeSet = pdTRUE; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 		/* Interrupts and other tasks can send to and receive from the queue
 | ||
|  | 		now the critical section has been exited. */ | ||
|  | 
 | ||
|  | 		vTaskSuspendAll(); | ||
|  | 		prvLockQueue( pxQueue ); | ||
|  | 
 | ||
|  | 		/* Update the timeout state to see if it has expired yet. */ | ||
|  | 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) | ||
|  | 		{ | ||
|  | 			if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) | ||
|  | 			{ | ||
|  | 				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); | ||
|  | 
 | ||
|  | 				#if ( configUSE_MUTEXES == 1 )
 | ||
|  | 				{ | ||
|  | 					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 					{ | ||
|  | 						portENTER_CRITICAL(); | ||
|  | 						{ | ||
|  | 							vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); | ||
|  | 						} | ||
|  | 						portEXIT_CRITICAL(); | ||
|  | 					} | ||
|  | 				} | ||
|  | 				#endif
 | ||
|  | 
 | ||
|  | 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); | ||
|  | 				prvUnlockQueue( pxQueue ); | ||
|  | 				if( xTaskResumeAll() == pdFALSE ) | ||
|  | 				{ | ||
|  | 					portYIELD_WITHIN_API(); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				/* Try again. */ | ||
|  | 				prvUnlockQueue( pxQueue ); | ||
|  | 				( void ) xTaskResumeAll(); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			prvUnlockQueue( pxQueue ); | ||
|  | 			( void ) xTaskResumeAll(); | ||
|  | 			traceQUEUE_RECEIVE_FAILED( pxQueue ); | ||
|  | 			return errQUEUE_EMPTY; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | unsigned portBASE_TYPE uxSavedInterruptStatus; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); | ||
|  | 
 | ||
|  | 	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); | ||
|  | 	{ | ||
|  | 		/* We cannot block from an ISR, so check there is data available. */ | ||
|  | 		if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 		{ | ||
|  | 			traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); | ||
|  | 
 | ||
|  | 			prvCopyDataFromQueue( pxQueue, pvBuffer ); | ||
|  | 			--( pxQueue->uxMessagesWaiting ); | ||
|  | 
 | ||
|  | 			/* If the queue is locked we will not modify the event list.  Instead
 | ||
|  | 			we update the lock count so the task that unlocks the queue will know | ||
|  | 			that an ISR has removed data while the queue was locked. */ | ||
|  | 			if( pxQueue->xRxLock == queueUNLOCKED ) | ||
|  | 			{ | ||
|  | 				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 				{ | ||
|  | 					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) | ||
|  | 					{ | ||
|  | 						/* The task waiting has a higher priority than us so
 | ||
|  | 						force a context switch. */ | ||
|  | 						if( pxHigherPriorityTaskWoken != NULL ) | ||
|  | 						{ | ||
|  | 							*pxHigherPriorityTaskWoken = pdTRUE; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				/* Increment the lock count so the task that unlocks the queue
 | ||
|  | 				knows that data was removed while it was locked. */ | ||
|  | 				++( pxQueue->xRxLock ); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			xReturn = pdPASS; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			xReturn = pdFAIL; | ||
|  | 			traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | unsigned portBASE_TYPE uxReturn; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 
 | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 		uxReturn = pxQueue->uxMessagesWaiting; | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 	return uxReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | unsigned portBASE_TYPE uxReturn; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 
 | ||
|  | 	uxReturn = pxQueue->uxMessagesWaiting; | ||
|  | 
 | ||
|  | 	return uxReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | void vQueueDelete( xQueueHandle pxQueue ) | ||
|  | { | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 
 | ||
|  | 	traceQUEUE_DELETE( pxQueue ); | ||
|  | 	vQueueUnregisterQueue( pxQueue ); | ||
|  | 	vPortFree( pxQueue->pcHead ); | ||
|  | 	vPortFree( pxQueue ); | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 
 | ||
|  | 	unsigned char ucQueueGetQueueNumber( xQueueHandle pxQueue ) | ||
|  | 	{ | ||
|  | 		return pxQueue->ucQueueNumber; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 
 | ||
|  | 	void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber ) | ||
|  | 	{ | ||
|  | 		pxQueue->ucQueueNumber = ucQueueNumber; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if ( configUSE_TRACE_FACILITY == 1 )
 | ||
|  | 
 | ||
|  | 	unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ) | ||
|  | 	{ | ||
|  | 		return pxQueue->ucQueueType; | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) | ||
|  | { | ||
|  | 	if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 	{ | ||
|  | 		#if ( configUSE_MUTEXES == 1 )
 | ||
|  | 		{ | ||
|  | 			if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) | ||
|  | 			{ | ||
|  | 				/* The mutex is no longer being held. */ | ||
|  | 				vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); | ||
|  | 				pxQueue->pxMutexHolder = NULL; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		#endif
 | ||
|  | 	} | ||
|  | 	else if( xPosition == queueSEND_TO_BACK ) | ||
|  | 	{ | ||
|  | 		memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); | ||
|  | 		pxQueue->pcWriteTo += pxQueue->uxItemSize; | ||
|  | 		if( pxQueue->pcWriteTo >= pxQueue->pcTail ) | ||
|  | 		{ | ||
|  | 			pxQueue->pcWriteTo = pxQueue->pcHead; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); | ||
|  | 		pxQueue->pcReadFrom -= pxQueue->uxItemSize; | ||
|  | 		if( pxQueue->pcReadFrom < pxQueue->pcHead ) | ||
|  | 		{ | ||
|  | 			pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	++( pxQueue->uxMessagesWaiting ); | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) | ||
|  | { | ||
|  | 	if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX ) | ||
|  | 	{ | ||
|  | 		pxQueue->pcReadFrom += pxQueue->uxItemSize; | ||
|  | 		if( pxQueue->pcReadFrom >= pxQueue->pcTail ) | ||
|  | 		{ | ||
|  | 			pxQueue->pcReadFrom = pxQueue->pcHead; | ||
|  | 		} | ||
|  | 		memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); | ||
|  | 	} | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | static void prvUnlockQueue( xQueueHandle pxQueue ) | ||
|  | { | ||
|  | 	/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ | ||
|  | 
 | ||
|  | 	/* The lock counts contains the number of extra data items placed or
 | ||
|  | 	removed from the queue while the queue was locked.  When a queue is | ||
|  | 	locked items can be added or removed, but the event lists cannot be | ||
|  | 	updated. */ | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 	{ | ||
|  | 		/* See if data was added to the queue while it was locked. */ | ||
|  | 		while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED ) | ||
|  | 		{ | ||
|  | 			/* Data was posted while the queue was locked.  Are any tasks
 | ||
|  | 			blocked waiting for data to become available? */ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				/* Tasks that are removed from the event list will get added to
 | ||
|  | 				the pending ready list as the scheduler is still suspended. */ | ||
|  | 				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					/* The task waiting has a higher priority so record that a
 | ||
|  | 					context	switch is required. */ | ||
|  | 					vTaskMissedYield(); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				--( pxQueue->xTxLock ); | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		pxQueue->xTxLock = queueUNLOCKED; | ||
|  | 	} | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 	/* Do the same for the Rx lock. */ | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 	{ | ||
|  | 		while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) | ||
|  | 		{ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					vTaskMissedYield(); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				--( pxQueue->xRxLock ); | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		pxQueue->xRxLock = queueUNLOCKED; | ||
|  | 	} | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 		xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ); | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	taskENTER_CRITICAL(); | ||
|  | 		xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength ); | ||
|  | 	taskEXIT_CRITICAL(); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	configASSERT( pxQueue ); | ||
|  | 	xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength ); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_CO_ROUTINES == 1
 | ||
|  | signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	/* If the queue is already full we may have to block.  A critical section
 | ||
|  | 	is required to prevent an interrupt removing something from the queue | ||
|  | 	between the check to see if the queue is full and blocking on the queue. */ | ||
|  | 	portDISABLE_INTERRUPTS(); | ||
|  | 	{ | ||
|  | 		if( prvIsQueueFull( pxQueue ) != pdFALSE ) | ||
|  | 		{ | ||
|  | 			/* The queue is full - do we want to block or just leave without
 | ||
|  | 			posting? */ | ||
|  | 			if( xTicksToWait > ( portTickType ) 0 ) | ||
|  | 			{ | ||
|  | 				/* As this is called from a coroutine we cannot block directly, but
 | ||
|  | 				return indicating that we need to block. */ | ||
|  | 				vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); | ||
|  | 				portENABLE_INTERRUPTS(); | ||
|  | 				return errQUEUE_BLOCKED; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				portENABLE_INTERRUPTS(); | ||
|  | 				return errQUEUE_FULL; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portENABLE_INTERRUPTS(); | ||
|  | 
 | ||
|  | 	portNOP(); | ||
|  | 
 | ||
|  | 	portDISABLE_INTERRUPTS(); | ||
|  | 	{ | ||
|  | 		if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) | ||
|  | 		{ | ||
|  | 			/* There is room in the queue, copy the data into the queue. */ | ||
|  | 			prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); | ||
|  | 			xReturn = pdPASS; | ||
|  | 
 | ||
|  | 			/* Were any co-routines waiting for data to become available? */ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				/* In this instance the co-routine could be placed directly
 | ||
|  | 				into the ready list as we are within a critical section. | ||
|  | 				Instead the same pending ready list mechanism is used as if | ||
|  | 				the event were caused from within an interrupt. */ | ||
|  | 				if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					/* The co-routine waiting has a higher priority so record
 | ||
|  | 					that a yield might be appropriate. */ | ||
|  | 					xReturn = errQUEUE_YIELD; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			xReturn = errQUEUE_FULL; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portENABLE_INTERRUPTS(); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_CO_ROUTINES == 1
 | ||
|  | signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	/* If the queue is already empty we may have to block.  A critical section
 | ||
|  | 	is required to prevent an interrupt adding something to the queue | ||
|  | 	between the check to see if the queue is empty and blocking on the queue. */ | ||
|  | 	portDISABLE_INTERRUPTS(); | ||
|  | 	{ | ||
|  | 		if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 		{ | ||
|  | 			/* There are no messages in the queue, do we want to block or just
 | ||
|  | 			leave with nothing? */ | ||
|  | 			if( xTicksToWait > ( portTickType ) 0 ) | ||
|  | 			{ | ||
|  | 				/* As this is a co-routine we cannot block directly, but return
 | ||
|  | 				indicating that we need to block. */ | ||
|  | 				vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); | ||
|  | 				portENABLE_INTERRUPTS(); | ||
|  | 				return errQUEUE_BLOCKED; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				portENABLE_INTERRUPTS(); | ||
|  | 				return errQUEUE_FULL; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portENABLE_INTERRUPTS(); | ||
|  | 
 | ||
|  | 	portNOP(); | ||
|  | 
 | ||
|  | 	portDISABLE_INTERRUPTS(); | ||
|  | 	{ | ||
|  | 		if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 		{ | ||
|  | 			/* Data is available from the queue. */ | ||
|  | 			pxQueue->pcReadFrom += pxQueue->uxItemSize; | ||
|  | 			if( pxQueue->pcReadFrom >= pxQueue->pcTail ) | ||
|  | 			{ | ||
|  | 				pxQueue->pcReadFrom = pxQueue->pcHead; | ||
|  | 			} | ||
|  | 			--( pxQueue->uxMessagesWaiting ); | ||
|  | 			memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); | ||
|  | 
 | ||
|  | 			xReturn = pdPASS; | ||
|  | 
 | ||
|  | 			/* Were any co-routines waiting for space to become available? */ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				/* In this instance the co-routine could be placed directly
 | ||
|  | 				into the ready list as we are within a critical section. | ||
|  | 				Instead the same pending ready list mechanism is used as if | ||
|  | 				the event were caused from within an interrupt. */ | ||
|  | 				if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					xReturn = errQUEUE_YIELD; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			xReturn = pdFAIL; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	portENABLE_INTERRUPTS(); | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #if configUSE_CO_ROUTINES == 1
 | ||
|  | signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) | ||
|  | { | ||
|  | 	/* Cannot block within an ISR so if there is no space on the queue then
 | ||
|  | 	exit without doing anything. */ | ||
|  | 	if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) | ||
|  | 	{ | ||
|  | 		prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); | ||
|  | 
 | ||
|  | 		/* We only want to wake one co-routine per ISR, so check that a
 | ||
|  | 		co-routine has not already been woken. */ | ||
|  | 		if( xCoRoutinePreviouslyWoken == pdFALSE ) | ||
|  | 		{ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					return pdTRUE; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return xCoRoutinePreviouslyWoken; | ||
|  | } | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_CO_ROUTINES == 1
 | ||
|  | signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken ) | ||
|  | { | ||
|  | signed portBASE_TYPE xReturn; | ||
|  | 
 | ||
|  | 	/* We cannot block from an ISR, so check there is data available. If
 | ||
|  | 	not then just leave without doing anything. */ | ||
|  | 	if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) | ||
|  | 	{ | ||
|  | 		/* Copy the data from the queue. */ | ||
|  | 		pxQueue->pcReadFrom += pxQueue->uxItemSize; | ||
|  | 		if( pxQueue->pcReadFrom >= pxQueue->pcTail ) | ||
|  | 		{ | ||
|  | 			pxQueue->pcReadFrom = pxQueue->pcHead; | ||
|  | 		} | ||
|  | 		--( pxQueue->uxMessagesWaiting ); | ||
|  | 		memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); | ||
|  | 
 | ||
|  | 		if( ( *pxCoRoutineWoken ) == pdFALSE ) | ||
|  | 		{ | ||
|  | 			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) | ||
|  | 			{ | ||
|  | 				if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) | ||
|  | 				{ | ||
|  | 					*pxCoRoutineWoken = pdTRUE; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		xReturn = pdPASS; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		xReturn = pdFAIL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return xReturn; | ||
|  | } | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configQUEUE_REGISTRY_SIZE > 0
 | ||
|  | 
 | ||
|  | 	void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) | ||
|  | 	{ | ||
|  | 	unsigned portBASE_TYPE ux; | ||
|  | 
 | ||
|  | 		/* See if there is an empty space in the registry.  A NULL name denotes
 | ||
|  | 		a free slot. */ | ||
|  | 		for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) | ||
|  | 		{ | ||
|  | 			if( xQueueRegistry[ ux ].pcQueueName == NULL ) | ||
|  | 			{ | ||
|  | 				/* Store the information on this queue. */ | ||
|  | 				xQueueRegistry[ ux ].pcQueueName = pcQueueName; | ||
|  | 				xQueueRegistry[ ux ].xHandle = xQueue; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configQUEUE_REGISTRY_SIZE > 0
 | ||
|  | 
 | ||
|  | 	static void vQueueUnregisterQueue( xQueueHandle xQueue ) | ||
|  | 	{ | ||
|  | 	unsigned portBASE_TYPE ux; | ||
|  | 
 | ||
|  | 		/* See if the handle of the queue being unregistered in actually in the
 | ||
|  | 		registry. */ | ||
|  | 		for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) | ||
|  | 		{ | ||
|  | 			if( xQueueRegistry[ ux ].xHandle == xQueue ) | ||
|  | 			{ | ||
|  | 				/* Set the name to NULL to show that this slot if free again. */ | ||
|  | 				xQueueRegistry[ ux ].pcQueueName = NULL; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | /*-----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #if configUSE_TIMERS == 1
 | ||
|  | 
 | ||
|  | 	void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) | ||
|  | 	{ | ||
|  | 		/* This function should not be called by application code hence the
 | ||
|  | 		'Restricted' in its name.  It is not part of the public API.  It is | ||
|  | 		designed for use by kernel code, and has special calling requirements. | ||
|  | 		It can result in vListInsert() being called on a list that can only | ||
|  | 		possibly ever have one item in it, so the list will be fast, but even | ||
|  | 		so it should be called with the scheduler locked and not from a critical | ||
|  | 		section. */ | ||
|  | 
 | ||
|  | 		/* Only do anything if there are no messages in the queue.  This function
 | ||
|  | 		will not actually cause the task to block, just place it on a blocked | ||
|  | 		list.  It will not block until the scheduler is unlocked - at which | ||
|  | 		time a yield will be performed.  If an item is added to the queue while | ||
|  | 		the queue is locked, and the calling task blocks on the queue, then the | ||
|  | 		calling task will be immediately unblocked when the queue is unlocked. */ | ||
|  | 		prvLockQueue( pxQueue ); | ||
|  | 		if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U ) | ||
|  | 		{ | ||
|  | 			/* There is nothing in the queue, block for the specified period. */ | ||
|  | 			vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); | ||
|  | 		} | ||
|  | 		prvUnlockQueue( pxQueue ); | ||
|  | 	} | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 |