blob: acd61195a7ddbc43b08c88343c8c19e8dd219672 [file] [log] [blame]
brians0ab60bb2013-01-31 02:21:51 +00001/*
2 FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.
3
4 ***************************************************************************
5 * *
6 * If you are: *
7 * *
8 * + New to FreeRTOS, *
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
10 * + Looking for basic training, *
11 * + Wanting to improve your FreeRTOS skills and productivity *
12 * *
13 * then take a look at the FreeRTOS eBook *
14 * *
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
16 * http://www.FreeRTOS.org/Documentation *
17 * *
18 * A pdf reference manual is also available. Both are usually delivered *
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
20 * and 8pm GMT (although please allow up to 24 hours in case of *
21 * exceptional circumstances). Thank you for your support! *
22 * *
23 ***************************************************************************
24
25 This file is part of the FreeRTOS distribution.
26
27 FreeRTOS is free software; you can redistribute it and/or modify it under
28 the terms of the GNU General Public License (version 2) as published by the
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
31 a combined work that includes FreeRTOS without being obliged to provide the
32 source code for proprietary components outside of the FreeRTOS kernel.
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
36 more details. You should have received a copy of the GNU General Public
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
39 by writing to Richard Barry, contact details for whom are available on the
40 FreeRTOS WEB site.
41
42 1 tab == 4 spaces!
43
44 http://www.FreeRTOS.org - Documentation, latest information, license and
45 contact details.
46
47 http://www.SafeRTOS.com - A version that is certified for use in safety
48 critical systems.
49
50 http://www.OpenRTOS.com - Commercial support, development, porting,
51 licensing and training services.
52*/
53
54#include <stdlib.h>
55#include <string.h>
56
57/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
58all the API functions to use the MPU wrappers. That should only be done when
59task.h is included from an application file. */
60#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
61
62#include "FreeRTOS.h"
63#include "task.h"
64#include "croutine.h"
65
66#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
67
68/*-----------------------------------------------------------
69 * PUBLIC LIST API documented in list.h
70 *----------------------------------------------------------*/
71
72/* Constants used with the cRxLock and cTxLock structure members. */
73#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
74#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 )
75
76#define queueERRONEOUS_UNBLOCK ( -1 )
77
78/* For internal use only. */
79#define queueSEND_TO_BACK ( 0 )
80#define queueSEND_TO_FRONT ( 1 )
81
82/* Effectively make a union out of the xQUEUE structure. */
83#define pxMutexHolder pcTail
84#define uxQueueType pcHead
85#define uxRecursiveCallCount pcReadFrom
86#define queueQUEUE_IS_MUTEX NULL
87
88/* Semaphores do not actually store or copy data, so have an items size of
89zero. */
90#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )
91#define queueDONT_BLOCK ( ( portTickType ) 0 )
92#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )
93
94/*
95 * Definition of the queue used by the scheduler.
96 * Items are queued by copy, not reference.
97 */
98typedef struct QueueDefinition {
99 signed char *pcHead; /*< Points to the beginning of the queue storage area. */
100 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. */
101
102 signed char *pcWriteTo; /*< Points to the free next place in the storage area. */
103 signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */
104
105 xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
106 xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
107
108 volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
109 unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
110 unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
111
112 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. */
113 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. */
114
115} xQUEUE;
116/*-----------------------------------------------------------*/
117
118/*
119 * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
120 * To keep the definition private the API header file defines it as a
121 * pointer to void.
122 */
123typedef xQUEUE * xQueueHandle;
124
125/*
126 * Prototypes for public functions are included here so we don't have to
127 * include the API header file (as it defines xQueueHandle differently). These
128 * functions are documented in the API header file.
129 */
130xQueueHandle xQueueCreate(unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize) PRIVILEGED_FUNCTION;
131signed portBASE_TYPE xQueueGenericSend(xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition) PRIVILEGED_FUNCTION;
132unsigned portBASE_TYPE uxQueueMessagesWaiting(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
133void vQueueDelete(xQueueHandle xQueue) PRIVILEGED_FUNCTION;
134signed portBASE_TYPE xQueueGenericSendFromISR(xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition) PRIVILEGED_FUNCTION;
135signed portBASE_TYPE xQueueGenericReceive(xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking) PRIVILEGED_FUNCTION;
136signed portBASE_TYPE xQueueReceiveFromISR(xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken) PRIVILEGED_FUNCTION;
137xQueueHandle xQueueCreateMutex(void) PRIVILEGED_FUNCTION;
138xQueueHandle xQueueCreateCountingSemaphore(unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount) PRIVILEGED_FUNCTION;
139portBASE_TYPE xQueueTakeMutexRecursive(xQueueHandle xMutex, portTickType xBlockTime) PRIVILEGED_FUNCTION;
140portBASE_TYPE xQueueGiveMutexRecursive(xQueueHandle xMutex) PRIVILEGED_FUNCTION;
141signed portBASE_TYPE xQueueAltGenericSend(xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition) PRIVILEGED_FUNCTION;
142signed portBASE_TYPE xQueueAltGenericReceive(xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking) PRIVILEGED_FUNCTION;
143signed portBASE_TYPE xQueueIsQueueEmptyFromISR(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
144signed portBASE_TYPE xQueueIsQueueFullFromISR(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
145unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
146
147/*
148 * Co-routine queue functions differ from task queue functions. Co-routines are
149 * an optional component.
150 */
151#if configUSE_CO_ROUTINES == 1
152signed portBASE_TYPE xQueueCRSendFromISR(xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken) PRIVILEGED_FUNCTION;
153signed portBASE_TYPE xQueueCRReceiveFromISR(xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken) PRIVILEGED_FUNCTION;
154signed portBASE_TYPE xQueueCRSend(xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait) PRIVILEGED_FUNCTION;
155signed portBASE_TYPE xQueueCRReceive(xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait) PRIVILEGED_FUNCTION;
156#endif
157
158/*
159 * The queue registry is just a means for kernel aware debuggers to locate
160 * queue structures. It has no other purpose so is an optional component.
161 */
162#if configQUEUE_REGISTRY_SIZE > 0
163
164/* The type stored within the queue registry array. This allows a name
165to be assigned to each queue making kernel aware debugging a little
166more user friendly. */
167typedef struct QUEUE_REGISTRY_ITEM {
168 signed char *pcQueueName;
169 xQueueHandle xHandle;
170} xQueueRegistryItem;
171
172/* The queue registry is simply an array of xQueueRegistryItem structures.
173The pcQueueName member of a structure being NULL is indicative of the
174array position being vacant. */
175xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];
176
177/* Removes a queue from the registry by simply setting the pcQueueName
178member to NULL. */
179static void vQueueUnregisterQueue(xQueueHandle xQueue) PRIVILEGED_FUNCTION;
180void vQueueAddToRegistry(xQueueHandle xQueue, signed char *pcQueueName) PRIVILEGED_FUNCTION;
181#endif
182
183/*
184 * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
185 * prevent an ISR from adding or removing items to the queue, but does prevent
186 * an ISR from removing tasks from the queue event lists. If an ISR finds a
187 * queue is locked it will instead increment the appropriate queue lock count
188 * to indicate that a task may require unblocking. When the queue in unlocked
189 * these lock counts are inspected, and the appropriate action taken.
190 */
191static void prvUnlockQueue(xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
192
193/*
194 * Uses a critical section to determine if there is any data in a queue.
195 *
196 * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
197 */
198static signed portBASE_TYPE prvIsQueueEmpty(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
199
200/*
201 * Uses a critical section to determine if there is any space in a queue.
202 *
203 * @return pdTRUE if there is no space, otherwise pdFALSE;
204 */
205static signed portBASE_TYPE prvIsQueueFull(const xQueueHandle pxQueue) PRIVILEGED_FUNCTION;
206
207/*
208 * Copies an item into the queue, either at the front of the queue or the
209 * back of the queue.
210 */
211static void prvCopyDataToQueue(xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition) PRIVILEGED_FUNCTION;
212
213/*
214 * Copies an item out of a queue.
215 */
216static void prvCopyDataFromQueue(xQUEUE * const pxQueue, const void *pvBuffer) PRIVILEGED_FUNCTION;
217/*-----------------------------------------------------------*/
218
219/*
220 * Macro to mark a queue as locked. Locking a queue prevents an ISR from
221 * accessing the queue event lists.
222 */
223#define prvLockQueue( pxQueue ) \
224{ \
225 taskENTER_CRITICAL(); \
226 { \
227 if( pxQueue->xRxLock == queueUNLOCKED ) \
228 { \
229 pxQueue->xRxLock = queueLOCKED_UNMODIFIED; \
230 } \
231 if( pxQueue->xTxLock == queueUNLOCKED ) \
232 { \
233 pxQueue->xTxLock = queueLOCKED_UNMODIFIED; \
234 } \
235 } \
236 taskEXIT_CRITICAL(); \
237}
238/*-----------------------------------------------------------*/
239
240
241/*-----------------------------------------------------------
242 * PUBLIC QUEUE MANAGEMENT API documented in queue.h
243 *----------------------------------------------------------*/
244
245xQueueHandle xQueueCreate(unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize)
246{
247 xQUEUE *pxNewQueue;
248 size_t xQueueSizeInBytes;
249
250 /* Allocate the new queue structure. */
251 if (uxQueueLength > (unsigned portBASE_TYPE) 0) {
252 pxNewQueue = (xQUEUE *) pvPortMalloc(sizeof(xQUEUE));
253 if (pxNewQueue != NULL) {
254 /* Create the list of pointers to queue items. The queue is one byte
255 longer than asked for to make wrap checking easier/faster. */
256 xQueueSizeInBytes = (size_t)(uxQueueLength * uxItemSize) + (size_t) 1;
257
258 pxNewQueue->pcHead = (signed char *) pvPortMalloc(xQueueSizeInBytes);
259 if (pxNewQueue->pcHead != NULL) {
260 /* Initialise the queue members as described above where the
261 queue type is defined. */
262 pxNewQueue->pcTail = pxNewQueue->pcHead + (uxQueueLength * uxItemSize);
263 pxNewQueue->uxMessagesWaiting = 0;
264 pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
265 pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ((uxQueueLength - 1) * uxItemSize);
266 pxNewQueue->uxLength = uxQueueLength;
267 pxNewQueue->uxItemSize = uxItemSize;
268 pxNewQueue->xRxLock = queueUNLOCKED;
269 pxNewQueue->xTxLock = queueUNLOCKED;
270
271 /* Likewise ensure the event queues start with the correct state. */
272 vListInitialise(&(pxNewQueue->xTasksWaitingToSend));
273 vListInitialise(&(pxNewQueue->xTasksWaitingToReceive));
274
275 traceQUEUE_CREATE(pxNewQueue);
276 return pxNewQueue;
277 } else {
278 traceQUEUE_CREATE_FAILED();
279 vPortFree(pxNewQueue);
280 }
281 }
282 }
283
284 /* Will only reach here if we could not allocate enough memory or no memory
285 was required. */
286 return NULL;
287}
288/*-----------------------------------------------------------*/
289
290#if ( configUSE_MUTEXES == 1 )
291
292xQueueHandle xQueueCreateMutex(void)
293{
294 xQUEUE *pxNewQueue;
295
296 /* Allocate the new queue structure. */
297 pxNewQueue = (xQUEUE *) pvPortMalloc(sizeof(xQUEUE));
298 if (pxNewQueue != NULL) {
299 /* Information required for priority inheritance. */
300 pxNewQueue->pxMutexHolder = NULL;
301 pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
302
303 /* Queues used as a mutex no data is actually copied into or out
304 of the queue. */
305 pxNewQueue->pcWriteTo = NULL;
306 pxNewQueue->pcReadFrom = NULL;
307
308 /* Each mutex has a length of 1 (like a binary semaphore) and
309 an item size of 0 as nothing is actually copied into or out
310 of the mutex. */
311 pxNewQueue->uxMessagesWaiting = 0;
312 pxNewQueue->uxLength = 1;
313 pxNewQueue->uxItemSize = 0;
314 pxNewQueue->xRxLock = queueUNLOCKED;
315 pxNewQueue->xTxLock = queueUNLOCKED;
316
317 /* Ensure the event queues start with the correct state. */
318 vListInitialise(&(pxNewQueue->xTasksWaitingToSend));
319 vListInitialise(&(pxNewQueue->xTasksWaitingToReceive));
320
321 /* Start with the semaphore in the expected state. */
322 xQueueGenericSend(pxNewQueue, NULL, 0, queueSEND_TO_BACK);
323
324 traceCREATE_MUTEX(pxNewQueue);
325 } else {
326 traceCREATE_MUTEX_FAILED();
327 }
328
329 return pxNewQueue;
330}
331
332#endif /* configUSE_MUTEXES */
333/*-----------------------------------------------------------*/
334
335#if configUSE_RECURSIVE_MUTEXES == 1
336
337portBASE_TYPE xQueueGiveMutexRecursive(xQueueHandle pxMutex)
338{
339 portBASE_TYPE xReturn;
340
341 /* If this is the task that holds the mutex then pxMutexHolder will not
342 change outside of this task. If this task does not hold the mutex then
343 pxMutexHolder can never coincidentally equal the tasks handle, and as
344 this is the only condition we are interested in it does not matter if
345 pxMutexHolder is accessed simultaneously by another task. Therefore no
346 mutual exclusion is required to test the pxMutexHolder variable. */
347 if (pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle()) {
348 traceGIVE_MUTEX_RECURSIVE(pxMutex);
349
350 /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
351 the task handle, therefore no underflow check is required. Also,
352 uxRecursiveCallCount is only modified by the mutex holder, and as
353 there can only be one, no mutual exclusion is required to modify the
354 uxRecursiveCallCount member. */
355 (pxMutex->uxRecursiveCallCount)--;
356
357 /* Have we unwound the call count? */
358 if (pxMutex->uxRecursiveCallCount == 0) {
359 /* Return the mutex. This will automatically unblock any other
360 task that might be waiting to access the mutex. */
361 xQueueGenericSend(pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK);
362 }
363
364 xReturn = pdPASS;
365 } else {
366 /* We cannot give the mutex because we are not the holder. */
367 xReturn = pdFAIL;
368
369 traceGIVE_MUTEX_RECURSIVE_FAILED(pxMutex);
370 }
371
372 return xReturn;
373}
374
375#endif /* configUSE_RECURSIVE_MUTEXES */
376/*-----------------------------------------------------------*/
377
378#if configUSE_RECURSIVE_MUTEXES == 1
379
380portBASE_TYPE xQueueTakeMutexRecursive(xQueueHandle pxMutex, portTickType xBlockTime)
381{
382 portBASE_TYPE xReturn;
383
384 /* Comments regarding mutual exclusion as per those within
385 xQueueGiveMutexRecursive(). */
386
387 traceTAKE_MUTEX_RECURSIVE(pxMutex);
388
389 if (pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle()) {
390 (pxMutex->uxRecursiveCallCount)++;
391 xReturn = pdPASS;
392 } else {
393 xReturn = xQueueGenericReceive(pxMutex, NULL, xBlockTime, pdFALSE);
394
395 /* pdPASS will only be returned if we successfully obtained the mutex,
396 we may have blocked to reach here. */
397 if (xReturn == pdPASS) {
398 (pxMutex->uxRecursiveCallCount)++;
399 }
400 }
401
402 return xReturn;
403}
404
405#endif /* configUSE_RECURSIVE_MUTEXES */
406/*-----------------------------------------------------------*/
407
408#if configUSE_COUNTING_SEMAPHORES == 1
409
410xQueueHandle xQueueCreateCountingSemaphore(unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount)
411{
412 xQueueHandle pxHandle;
413
414 pxHandle = xQueueCreate((unsigned portBASE_TYPE) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH);
415
416 if (pxHandle != NULL) {
417 pxHandle->uxMessagesWaiting = uxInitialCount;
418
419 traceCREATE_COUNTING_SEMAPHORE();
420 } else {
421 traceCREATE_COUNTING_SEMAPHORE_FAILED();
422 }
423
424 return pxHandle;
425}
426
427#endif /* configUSE_COUNTING_SEMAPHORES */
428/*-----------------------------------------------------------*/
429
430signed portBASE_TYPE xQueueGenericSend(xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition)
431{
432 signed portBASE_TYPE xEntryTimeSet = pdFALSE;
433 xTimeOutType xTimeOut;
434
435 /* This function relaxes the coding standard somewhat to allow return
436 statements within the function itself. This is done in the interest
437 of execution time efficiency. */
438 for (;;) {
439 taskENTER_CRITICAL();
440 {
441 /* Is there room on the queue now? To be running we must be
442 the highest priority task wanting to access the queue. */
443 if (pxQueue->uxMessagesWaiting < pxQueue->uxLength) {
444 traceQUEUE_SEND(pxQueue);
445 prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);
446
447 /* If there was a task waiting for data to arrive on the
448 queue then unblock it now. */
449 if (listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE) {
450 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) == pdTRUE) {
451 /* The unblocked task has a priority higher than
452 our own so yield immediately. Yes it is ok to do
453 this from within the critical section - the kernel
454 takes care of that. */
455 portYIELD_WITHIN_API();
456 }
457 }
458
459 taskEXIT_CRITICAL();
460
461 /* Return to the original privilege level before exiting the
462 function. */
463 return pdPASS;
464 } else {
465 if (xTicksToWait == (portTickType) 0) {
466 /* The queue was full and no block time is specified (or
467 the block time has expired) so leave now. */
468 taskEXIT_CRITICAL();
469
470 /* Return to the original privilege level before exiting
471 the function. */
472 traceQUEUE_SEND_FAILED(pxQueue);
473 return errQUEUE_FULL;
474 } else if (xEntryTimeSet == pdFALSE) {
475 /* The queue was full and a block time was specified so
476 configure the timeout structure. */
477 vTaskSetTimeOutState(&xTimeOut);
478 xEntryTimeSet = pdTRUE;
479 }
480 }
481 }
482 taskEXIT_CRITICAL();
483
484 /* Interrupts and other tasks can send to and receive from the queue
485 now the critical section has been exited. */
486
487 vTaskSuspendAll();
488 prvLockQueue(pxQueue);
489
490 /* Update the timeout state to see if it has expired yet. */
491 if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE) {
492 if (prvIsQueueFull(pxQueue)) {
493 traceBLOCKING_ON_QUEUE_SEND(pxQueue);
494 vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToSend), xTicksToWait);
495
496 /* Unlocking the queue means queue events can effect the
497 event list. It is possible that interrupts occurring now
498 remove this task from the event list again - but as the
499 scheduler is suspended the task will go onto the pending
500 ready last instead of the actual ready list. */
501 prvUnlockQueue(pxQueue);
502
503 /* Resuming the scheduler will move tasks from the pending
504 ready list into the ready list - so it is feasible that this
505 task is already in a ready list before it yields - in which
506 case the yield will not cause a context switch unless there
507 is also a higher priority task in the pending ready list. */
508 if (!xTaskResumeAll()) {
509 portYIELD_WITHIN_API();
510 }
511 } else {
512 /* Try again. */
513 prvUnlockQueue(pxQueue);
514 (void) xTaskResumeAll();
515 }
516 } else {
517 /* The timeout has expired. */
518 prvUnlockQueue(pxQueue);
519 (void) xTaskResumeAll();
520
521 /* Return to the original privilege level before exiting the
522 function. */
523 traceQUEUE_SEND_FAILED(pxQueue);
524 return errQUEUE_FULL;
525 }
526 }
527}
528/*-----------------------------------------------------------*/
529
530#if configUSE_ALTERNATIVE_API == 1
531
532signed portBASE_TYPE xQueueAltGenericSend(xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition)
533{
534 signed portBASE_TYPE xEntryTimeSet = pdFALSE;
535 xTimeOutType xTimeOut;
536
537 for (;;) {
538 taskENTER_CRITICAL();
539 {
540 /* Is there room on the queue now? To be running we must be
541 the highest priority task wanting to access the queue. */
542 if (pxQueue->uxMessagesWaiting < pxQueue->uxLength) {
543 traceQUEUE_SEND(pxQueue);
544 prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);
545
546 /* If there was a task waiting for data to arrive on the
547 queue then unblock it now. */
548 if (listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE) {
549 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) == pdTRUE) {
550 /* The unblocked task has a priority higher than
551 our own so yield immediately. */
552 portYIELD_WITHIN_API();
553 }
554 }
555
556 taskEXIT_CRITICAL();
557 return pdPASS;
558 } else {
559 if (xTicksToWait == (portTickType) 0) {
560 taskEXIT_CRITICAL();
561 return errQUEUE_FULL;
562 } else if (xEntryTimeSet == pdFALSE) {
563 vTaskSetTimeOutState(&xTimeOut);
564 xEntryTimeSet = pdTRUE;
565 }
566 }
567 }
568 taskEXIT_CRITICAL();
569
570 taskENTER_CRITICAL();
571 {
572 if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE) {
573 if (prvIsQueueFull(pxQueue)) {
574 traceBLOCKING_ON_QUEUE_SEND(pxQueue);
575 vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToSend), xTicksToWait);
576 portYIELD_WITHIN_API();
577 }
578 } else {
579 taskEXIT_CRITICAL();
580 traceQUEUE_SEND_FAILED(pxQueue);
581 return errQUEUE_FULL;
582 }
583 }
584 taskEXIT_CRITICAL();
585 }
586}
587
588#endif /* configUSE_ALTERNATIVE_API */
589/*-----------------------------------------------------------*/
590
591#if configUSE_ALTERNATIVE_API == 1
592
593signed portBASE_TYPE xQueueAltGenericReceive(xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking)
594{
595 signed portBASE_TYPE xEntryTimeSet = pdFALSE;
596 xTimeOutType xTimeOut;
597 signed char *pcOriginalReadPosition;
598
599 for (;;) {
600 taskENTER_CRITICAL();
601 {
602 if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0) {
603 /* Remember our read position in case we are just peeking. */
604 pcOriginalReadPosition = pxQueue->pcReadFrom;
605
606 prvCopyDataFromQueue(pxQueue, pvBuffer);
607
608 if (xJustPeeking == pdFALSE) {
609 traceQUEUE_RECEIVE(pxQueue);
610
611 /* We are actually removing data. */
612 --(pxQueue->uxMessagesWaiting);
613
614#if ( configUSE_MUTEXES == 1 )
615 {
616 if (pxQueue->uxQueueType == queueQUEUE_IS_MUTEX) {
617 /* Record the information required to implement
618 priority inheritance should it become necessary. */
619 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
620 }
621 }
622#endif
623
624 if (listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend)) == pdFALSE) {
625 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) == pdTRUE) {
626 portYIELD_WITHIN_API();
627 }
628 }
629 } else {
630 traceQUEUE_PEEK(pxQueue);
631
632 /* We are not removing the data, so reset our read
633 pointer. */
634 pxQueue->pcReadFrom = pcOriginalReadPosition;
635
636 /* The data is being left in the queue, so see if there are
637 any other tasks waiting for the data. */
638 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
639 /* Tasks that are removed from the event list will get added to
640 the pending ready list as the scheduler is still suspended. */
641 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
642 /* The task waiting has a higher priority than this task. */
643 portYIELD_WITHIN_API();
644 }
645 }
646
647 }
648
649 taskEXIT_CRITICAL();
650 return pdPASS;
651 } else {
652 if (xTicksToWait == (portTickType) 0) {
653 taskEXIT_CRITICAL();
654 traceQUEUE_RECEIVE_FAILED(pxQueue);
655 return errQUEUE_EMPTY;
656 } else if (xEntryTimeSet == pdFALSE) {
657 vTaskSetTimeOutState(&xTimeOut);
658 xEntryTimeSet = pdTRUE;
659 }
660 }
661 }
662 taskEXIT_CRITICAL();
663
664 taskENTER_CRITICAL();
665 {
666 if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE) {
667 if (prvIsQueueEmpty(pxQueue)) {
668 traceBLOCKING_ON_QUEUE_RECEIVE(pxQueue);
669
670#if ( configUSE_MUTEXES == 1 )
671 {
672 if (pxQueue->uxQueueType == queueQUEUE_IS_MUTEX) {
673 portENTER_CRITICAL();
674 vTaskPriorityInherit((void *) pxQueue->pxMutexHolder);
675 portEXIT_CRITICAL();
676 }
677 }
678#endif
679
680 vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToReceive), xTicksToWait);
681 portYIELD_WITHIN_API();
682 }
683 } else {
684 taskEXIT_CRITICAL();
685 traceQUEUE_RECEIVE_FAILED(pxQueue);
686 return errQUEUE_EMPTY;
687 }
688 }
689 taskEXIT_CRITICAL();
690 }
691}
692
693
694#endif /* configUSE_ALTERNATIVE_API */
695/*-----------------------------------------------------------*/
696
697signed portBASE_TYPE xQueueGenericSendFromISR(xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition)
698{
699 signed portBASE_TYPE xReturn;
700 unsigned portBASE_TYPE uxSavedInterruptStatus;
701
702 /* Similar to xQueueGenericSend, except we don't block if there is no room
703 in the queue. Also we don't directly wake a task that was blocked on a
704 queue read, instead we return a flag to say whether a context switch is
705 required or not (i.e. has a task with a higher priority than us been woken
706 by this post). */
707 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
708 {
709 if (pxQueue->uxMessagesWaiting < pxQueue->uxLength) {
710 traceQUEUE_SEND_FROM_ISR(pxQueue);
711
712 prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);
713
714 /* If the queue is locked we do not alter the event list. This will
715 be done when the queue is unlocked later. */
716 if (pxQueue->xTxLock == queueUNLOCKED) {
717 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
718 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
719 /* The task waiting has a higher priority so record that a
720 context switch is required. */
721 *pxHigherPriorityTaskWoken = pdTRUE;
722 }
723 }
724 } else {
725 /* Increment the lock count so the task that unlocks the queue
726 knows that data was posted while it was locked. */
727 ++(pxQueue->xTxLock);
728 }
729
730 xReturn = pdPASS;
731 } else {
732 traceQUEUE_SEND_FROM_ISR_FAILED(pxQueue);
733 xReturn = errQUEUE_FULL;
734 }
735 }
736 portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
737
738 return xReturn;
739}
740/*-----------------------------------------------------------*/
741
742signed portBASE_TYPE xQueueGenericReceive(xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking)
743{
744 signed portBASE_TYPE xEntryTimeSet = pdFALSE;
745 xTimeOutType xTimeOut;
746 signed char *pcOriginalReadPosition;
747
748 /* This function relaxes the coding standard somewhat to allow return
749 statements within the function itself. This is done in the interest
750 of execution time efficiency. */
751
752 for (;;) {
753 taskENTER_CRITICAL();
754 {
755 /* Is there data in the queue now? To be running we must be
756 the highest priority task wanting to access the queue. */
757 if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0) {
758 /* Remember our read position in case we are just peeking. */
759 pcOriginalReadPosition = pxQueue->pcReadFrom;
760
761 prvCopyDataFromQueue(pxQueue, pvBuffer);
762
763 if (xJustPeeking == pdFALSE) {
764 traceQUEUE_RECEIVE(pxQueue);
765
766 /* We are actually removing data. */
767 --(pxQueue->uxMessagesWaiting);
768
769#if ( configUSE_MUTEXES == 1 )
770 {
771 if (pxQueue->uxQueueType == queueQUEUE_IS_MUTEX) {
772 /* Record the information required to implement
773 priority inheritance should it become necessary. */
774 pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
775 }
776 }
777#endif
778
779 if (listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend)) == pdFALSE) {
780 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) == pdTRUE) {
781 portYIELD_WITHIN_API();
782 }
783 }
784 } else {
785 traceQUEUE_PEEK(pxQueue);
786
787 /* We are not removing the data, so reset our read
788 pointer. */
789 pxQueue->pcReadFrom = pcOriginalReadPosition;
790
791 /* The data is being left in the queue, so see if there are
792 any other tasks waiting for the data. */
793 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
794 /* Tasks that are removed from the event list will get added to
795 the pending ready list as the scheduler is still suspended. */
796 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
797 /* The task waiting has a higher priority than this task. */
798 portYIELD_WITHIN_API();
799 }
800 }
801
802 }
803
804 taskEXIT_CRITICAL();
805 return pdPASS;
806 } else {
807 if (xTicksToWait == (portTickType) 0) {
808 /* The queue was empty and no block time is specified (or
809 the block time has expired) so leave now. */
810 taskEXIT_CRITICAL();
811 traceQUEUE_RECEIVE_FAILED(pxQueue);
812 return errQUEUE_EMPTY;
813 } else if (xEntryTimeSet == pdFALSE) {
814 /* The queue was empty and a block time was specified so
815 configure the timeout structure. */
816 vTaskSetTimeOutState(&xTimeOut);
817 xEntryTimeSet = pdTRUE;
818 }
819 }
820 }
821 taskEXIT_CRITICAL();
822
823 /* Interrupts and other tasks can send to and receive from the queue
824 now the critical section has been exited. */
825
826 vTaskSuspendAll();
827 prvLockQueue(pxQueue);
828
829 /* Update the timeout state to see if it has expired yet. */
830 if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE) {
831 if (prvIsQueueEmpty(pxQueue)) {
832 traceBLOCKING_ON_QUEUE_RECEIVE(pxQueue);
833
834#if ( configUSE_MUTEXES == 1 )
835 {
836 if (pxQueue->uxQueueType == queueQUEUE_IS_MUTEX) {
837 portENTER_CRITICAL();
838 {
839 vTaskPriorityInherit((void *) pxQueue->pxMutexHolder);
840 }
841 portEXIT_CRITICAL();
842 }
843 }
844#endif
845
846 vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToReceive), xTicksToWait);
847 prvUnlockQueue(pxQueue);
848 if (!xTaskResumeAll()) {
849 portYIELD_WITHIN_API();
850 }
851 } else {
852 /* Try again. */
853 prvUnlockQueue(pxQueue);
854 (void) xTaskResumeAll();
855 }
856 } else {
857 prvUnlockQueue(pxQueue);
858 (void) xTaskResumeAll();
859 traceQUEUE_RECEIVE_FAILED(pxQueue);
860 return errQUEUE_EMPTY;
861 }
862 }
863}
864/*-----------------------------------------------------------*/
865
866signed portBASE_TYPE xQueueReceiveFromISR(xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken)
867{
868 signed portBASE_TYPE xReturn;
869 unsigned portBASE_TYPE uxSavedInterruptStatus;
870
871 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
872 {
873 /* We cannot block from an ISR, so check there is data available. */
874 if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0) {
875 traceQUEUE_RECEIVE_FROM_ISR(pxQueue);
876
877 prvCopyDataFromQueue(pxQueue, pvBuffer);
878 --(pxQueue->uxMessagesWaiting);
879
880 /* If the queue is locked we will not modify the event list. Instead
881 we update the lock count so the task that unlocks the queue will know
882 that an ISR has removed data while the queue was locked. */
883 if (pxQueue->xRxLock == queueUNLOCKED) {
884 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend))) {
885 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE) {
886 /* The task waiting has a higher priority than us so
887 force a context switch. */
888 *pxTaskWoken = pdTRUE;
889 }
890 }
891 } else {
892 /* Increment the lock count so the task that unlocks the queue
893 knows that data was removed while it was locked. */
894 ++(pxQueue->xRxLock);
895 }
896
897 xReturn = pdPASS;
898 } else {
899 xReturn = pdFAIL;
900 traceQUEUE_RECEIVE_FROM_ISR_FAILED(pxQueue);
901 }
902 }
903 portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
904
905 return xReturn;
906}
907/*-----------------------------------------------------------*/
908
909unsigned portBASE_TYPE uxQueueMessagesWaiting(const xQueueHandle pxQueue)
910{
911 unsigned portBASE_TYPE uxReturn;
912
913 taskENTER_CRITICAL();
914 uxReturn = pxQueue->uxMessagesWaiting;
915 taskEXIT_CRITICAL();
916
917 return uxReturn;
918}
919/*-----------------------------------------------------------*/
920
921unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR(const xQueueHandle pxQueue)
922{
923 unsigned portBASE_TYPE uxReturn;
924
925 uxReturn = pxQueue->uxMessagesWaiting;
926
927 return uxReturn;
928}
929/*-----------------------------------------------------------*/
930
931void vQueueDelete(xQueueHandle pxQueue)
932{
933 traceQUEUE_DELETE(pxQueue);
934 vQueueUnregisterQueue(pxQueue);
935 vPortFree(pxQueue->pcHead);
936 vPortFree(pxQueue);
937}
938/*-----------------------------------------------------------*/
939
940static void prvCopyDataToQueue(xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition)
941{
942 if (pxQueue->uxItemSize == (unsigned portBASE_TYPE) 0) {
943#if ( configUSE_MUTEXES == 1 )
944 {
945 if (pxQueue->uxQueueType == queueQUEUE_IS_MUTEX) {
946 /* The mutex is no longer being held. */
947 vTaskPriorityDisinherit((void *) pxQueue->pxMutexHolder);
948 pxQueue->pxMutexHolder = NULL;
949 }
950 }
951#endif
952 } else if (xPosition == queueSEND_TO_BACK) {
953 memcpy((void *) pxQueue->pcWriteTo, pvItemToQueue, (unsigned) pxQueue->uxItemSize);
954 pxQueue->pcWriteTo += pxQueue->uxItemSize;
955 if (pxQueue->pcWriteTo >= pxQueue->pcTail) {
956 pxQueue->pcWriteTo = pxQueue->pcHead;
957 }
958 } else {
959 memcpy((void *) pxQueue->pcReadFrom, pvItemToQueue, (unsigned) pxQueue->uxItemSize);
960 pxQueue->pcReadFrom -= pxQueue->uxItemSize;
961 if (pxQueue->pcReadFrom < pxQueue->pcHead) {
962 pxQueue->pcReadFrom = (pxQueue->pcTail - pxQueue->uxItemSize);
963 }
964 }
965
966 ++(pxQueue->uxMessagesWaiting);
967}
968/*-----------------------------------------------------------*/
969
970static void prvCopyDataFromQueue(xQUEUE * const pxQueue, const void *pvBuffer)
971{
972 if (pxQueue->uxQueueType != queueQUEUE_IS_MUTEX) {
973 pxQueue->pcReadFrom += pxQueue->uxItemSize;
974 if (pxQueue->pcReadFrom >= pxQueue->pcTail) {
975 pxQueue->pcReadFrom = pxQueue->pcHead;
976 }
977 memcpy((void *) pvBuffer, (void *) pxQueue->pcReadFrom, (unsigned) pxQueue->uxItemSize);
978 }
979}
980/*-----------------------------------------------------------*/
981
982static void prvUnlockQueue(xQueueHandle pxQueue)
983{
984 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
985
986 /* The lock counts contains the number of extra data items placed or
987 removed from the queue while the queue was locked. When a queue is
988 locked items can be added or removed, but the event lists cannot be
989 updated. */
990 taskENTER_CRITICAL();
991 {
992 /* See if data was added to the queue while it was locked. */
993 while (pxQueue->xTxLock > queueLOCKED_UNMODIFIED) {
994 /* Data was posted while the queue was locked. Are any tasks
995 blocked waiting for data to become available? */
996 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
997 /* Tasks that are removed from the event list will get added to
998 the pending ready list as the scheduler is still suspended. */
999 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
1000 /* The task waiting has a higher priority so record that a
1001 context switch is required. */
1002 vTaskMissedYield();
1003 }
1004
1005 --(pxQueue->xTxLock);
1006 } else {
1007 break;
1008 }
1009 }
1010
1011 pxQueue->xTxLock = queueUNLOCKED;
1012 }
1013 taskEXIT_CRITICAL();
1014
1015 /* Do the same for the Rx lock. */
1016 taskENTER_CRITICAL();
1017 {
1018 while (pxQueue->xRxLock > queueLOCKED_UNMODIFIED) {
1019 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend))) {
1020 if (xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE) {
1021 vTaskMissedYield();
1022 }
1023
1024 --(pxQueue->xRxLock);
1025 } else {
1026 break;
1027 }
1028 }
1029
1030 pxQueue->xRxLock = queueUNLOCKED;
1031 }
1032 taskEXIT_CRITICAL();
1033}
1034/*-----------------------------------------------------------*/
1035
1036static signed portBASE_TYPE prvIsQueueEmpty(const xQueueHandle pxQueue)
1037{
1038 signed portBASE_TYPE xReturn;
1039
1040 taskENTER_CRITICAL();
1041 xReturn = (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0);
1042 taskEXIT_CRITICAL();
1043
1044 return xReturn;
1045}
1046/*-----------------------------------------------------------*/
1047
1048signed portBASE_TYPE xQueueIsQueueEmptyFromISR(const xQueueHandle pxQueue)
1049{
1050 signed portBASE_TYPE xReturn;
1051
1052 xReturn = (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0);
1053
1054 return xReturn;
1055}
1056/*-----------------------------------------------------------*/
1057
1058static signed portBASE_TYPE prvIsQueueFull(const xQueueHandle pxQueue)
1059{
1060 signed portBASE_TYPE xReturn;
1061
1062 taskENTER_CRITICAL();
1063 xReturn = (pxQueue->uxMessagesWaiting == pxQueue->uxLength);
1064 taskEXIT_CRITICAL();
1065
1066 return xReturn;
1067}
1068/*-----------------------------------------------------------*/
1069
1070signed portBASE_TYPE xQueueIsQueueFullFromISR(const xQueueHandle pxQueue)
1071{
1072 signed portBASE_TYPE xReturn;
1073
1074 xReturn = (pxQueue->uxMessagesWaiting == pxQueue->uxLength);
1075
1076 return xReturn;
1077}
1078/*-----------------------------------------------------------*/
1079
1080#if configUSE_CO_ROUTINES == 1
1081signed portBASE_TYPE xQueueCRSend(xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait)
1082{
1083 signed portBASE_TYPE xReturn;
1084
1085 /* If the queue is already full we may have to block. A critical section
1086 is required to prevent an interrupt removing something from the queue
1087 between the check to see if the queue is full and blocking on the queue. */
1088 portDISABLE_INTERRUPTS();
1089 {
1090 if (prvIsQueueFull(pxQueue)) {
1091 /* The queue is full - do we want to block or just leave without
1092 posting? */
1093 if (xTicksToWait > (portTickType) 0) {
1094 /* As this is called from a coroutine we cannot block directly, but
1095 return indicating that we need to block. */
1096 vCoRoutineAddToDelayedList(xTicksToWait, &(pxQueue->xTasksWaitingToSend));
1097 portENABLE_INTERRUPTS();
1098 return errQUEUE_BLOCKED;
1099 } else {
1100 portENABLE_INTERRUPTS();
1101 return errQUEUE_FULL;
1102 }
1103 }
1104 }
1105 portENABLE_INTERRUPTS();
1106
1107 portNOP();
1108
1109 portDISABLE_INTERRUPTS();
1110 {
1111 if (pxQueue->uxMessagesWaiting < pxQueue->uxLength) {
1112 /* There is room in the queue, copy the data into the queue. */
1113 prvCopyDataToQueue(pxQueue, pvItemToQueue, queueSEND_TO_BACK);
1114 xReturn = pdPASS;
1115
1116 /* Were any co-routines waiting for data to become available? */
1117 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
1118 /* In this instance the co-routine could be placed directly
1119 into the ready list as we are within a critical section.
1120 Instead the same pending ready list mechanism is used as if
1121 the event were caused from within an interrupt. */
1122 if (xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
1123 /* The co-routine waiting has a higher priority so record
1124 that a yield might be appropriate. */
1125 xReturn = errQUEUE_YIELD;
1126 }
1127 }
1128 } else {
1129 xReturn = errQUEUE_FULL;
1130 }
1131 }
1132 portENABLE_INTERRUPTS();
1133
1134 return xReturn;
1135}
1136#endif
1137/*-----------------------------------------------------------*/
1138
1139#if configUSE_CO_ROUTINES == 1
1140signed portBASE_TYPE xQueueCRReceive(xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait)
1141{
1142 signed portBASE_TYPE xReturn;
1143
1144 /* If the queue is already empty we may have to block. A critical section
1145 is required to prevent an interrupt adding something to the queue
1146 between the check to see if the queue is empty and blocking on the queue. */
1147 portDISABLE_INTERRUPTS();
1148 {
1149 if (pxQueue->uxMessagesWaiting == (unsigned portBASE_TYPE) 0) {
1150 /* There are no messages in the queue, do we want to block or just
1151 leave with nothing? */
1152 if (xTicksToWait > (portTickType) 0) {
1153 /* As this is a co-routine we cannot block directly, but return
1154 indicating that we need to block. */
1155 vCoRoutineAddToDelayedList(xTicksToWait, &(pxQueue->xTasksWaitingToReceive));
1156 portENABLE_INTERRUPTS();
1157 return errQUEUE_BLOCKED;
1158 } else {
1159 portENABLE_INTERRUPTS();
1160 return errQUEUE_FULL;
1161 }
1162 }
1163 }
1164 portENABLE_INTERRUPTS();
1165
1166 portNOP();
1167
1168 portDISABLE_INTERRUPTS();
1169 {
1170 if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0) {
1171 /* Data is available from the queue. */
1172 pxQueue->pcReadFrom += pxQueue->uxItemSize;
1173 if (pxQueue->pcReadFrom >= pxQueue->pcTail) {
1174 pxQueue->pcReadFrom = pxQueue->pcHead;
1175 }
1176 --(pxQueue->uxMessagesWaiting);
1177 memcpy((void *) pvBuffer, (void *) pxQueue->pcReadFrom, (unsigned) pxQueue->uxItemSize);
1178
1179 xReturn = pdPASS;
1180
1181 /* Were any co-routines waiting for space to become available? */
1182 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend))) {
1183 /* In this instance the co-routine could be placed directly
1184 into the ready list as we are within a critical section.
1185 Instead the same pending ready list mechanism is used as if
1186 the event were caused from within an interrupt. */
1187 if (xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE) {
1188 xReturn = errQUEUE_YIELD;
1189 }
1190 }
1191 } else {
1192 xReturn = pdFAIL;
1193 }
1194 }
1195 portENABLE_INTERRUPTS();
1196
1197 return xReturn;
1198}
1199#endif
1200/*-----------------------------------------------------------*/
1201
1202
1203
1204#if configUSE_CO_ROUTINES == 1
1205signed portBASE_TYPE xQueueCRSendFromISR(xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken)
1206{
1207 /* Cannot block within an ISR so if there is no space on the queue then
1208 exit without doing anything. */
1209 if (pxQueue->uxMessagesWaiting < pxQueue->uxLength) {
1210 prvCopyDataToQueue(pxQueue, pvItemToQueue, queueSEND_TO_BACK);
1211
1212 /* We only want to wake one co-routine per ISR, so check that a
1213 co-routine has not already been woken. */
1214 if (!xCoRoutinePreviouslyWoken) {
1215 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive))) {
1216 if (xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE) {
1217 return pdTRUE;
1218 }
1219 }
1220 }
1221 }
1222
1223 return xCoRoutinePreviouslyWoken;
1224}
1225#endif
1226/*-----------------------------------------------------------*/
1227
1228#if configUSE_CO_ROUTINES == 1
1229signed portBASE_TYPE xQueueCRReceiveFromISR(xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken)
1230{
1231 signed portBASE_TYPE xReturn;
1232
1233 /* We cannot block from an ISR, so check there is data available. If
1234 not then just leave without doing anything. */
1235 if (pxQueue->uxMessagesWaiting > (unsigned portBASE_TYPE) 0) {
1236 /* Copy the data from the queue. */
1237 pxQueue->pcReadFrom += pxQueue->uxItemSize;
1238 if (pxQueue->pcReadFrom >= pxQueue->pcTail) {
1239 pxQueue->pcReadFrom = pxQueue->pcHead;
1240 }
1241 --(pxQueue->uxMessagesWaiting);
1242 memcpy((void *) pvBuffer, (void *) pxQueue->pcReadFrom, (unsigned) pxQueue->uxItemSize);
1243
1244 if (!(*pxCoRoutineWoken)) {
1245 if (!listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend))) {
1246 if (xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE) {
1247 *pxCoRoutineWoken = pdTRUE;
1248 }
1249 }
1250 }
1251
1252 xReturn = pdPASS;
1253 } else {
1254 xReturn = pdFAIL;
1255 }
1256
1257 return xReturn;
1258}
1259#endif
1260/*-----------------------------------------------------------*/
1261
1262#if configQUEUE_REGISTRY_SIZE > 0
1263
1264void vQueueAddToRegistry(xQueueHandle xQueue, signed char *pcQueueName)
1265{
1266 unsigned portBASE_TYPE ux;
1267
1268 /* See if there is an empty space in the registry. A NULL name denotes
1269 a free slot. */
1270 for (ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++) {
1271 if (xQueueRegistry[ ux ].pcQueueName == NULL) {
1272 /* Store the information on this queue. */
1273 xQueueRegistry[ ux ].pcQueueName = pcQueueName;
1274 xQueueRegistry[ ux ].xHandle = xQueue;
1275 break;
1276 }
1277 }
1278}
1279
1280#endif
1281/*-----------------------------------------------------------*/
1282
1283#if configQUEUE_REGISTRY_SIZE > 0
1284
1285static void vQueueUnregisterQueue(xQueueHandle xQueue)
1286{
1287 unsigned portBASE_TYPE ux;
1288
1289 /* See if the handle of the queue being unregistered in actually in the
1290 registry. */
1291 for (ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++) {
1292 if (xQueueRegistry[ ux ].xHandle == xQueue) {
1293 /* Set the name to NULL to show that this slot if free again. */
1294 xQueueRegistry[ ux ].pcQueueName = NULL;
1295 break;
1296 }
1297 }
1298
1299}
1300
1301#endif
1302