--- /dev/null
+/*\r
+ FreeRTOS V7.1.0 - Copyright (C) 2011 Real Time Engineers Ltd.\r
+\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS tutorial books are available in pdf and paperback. *\r
+ * Complete, revised, and edited pdf reference manuals are also *\r
+ * available. *\r
+ * *\r
+ * Purchasing FreeRTOS documentation will not only help you, by *\r
+ * ensuring you get running as quickly as possible and with an *\r
+ * in-depth knowledge of how to use FreeRTOS, it will also help *\r
+ * the FreeRTOS project to continue with its mission of providing *\r
+ * professional grade, cross platform, de facto standard solutions *\r
+ * for microcontrollers - completely free of charge! *\r
+ * *\r
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
+ * *\r
+ * Thank you for using FreeRTOS, and thank you for your support! *\r
+ * *\r
+ ***************************************************************************\r
+\r
+\r
+ This file is part of the FreeRTOS distribution.\r
+\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+ >>>NOTE<<< The modification to the GPL is included to allow you to\r
+ distribute a combined work that includes FreeRTOS without being obliged to\r
+ provide the source code for proprietary components outside of the FreeRTOS\r
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+ more details. You should have received a copy of the GNU General Public\r
+ License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+ by writing to Richard Barry, contact details for whom are available on the\r
+ FreeRTOS WEB site.\r
+\r
+ 1 tab == 4 spaces!\r
+\r
+ http://www.FreeRTOS.org - Documentation, latest information, license and\r
+ contact details.\r
+\r
+ http://www.SafeRTOS.com - A version that is certified for use in safety\r
+ critical systems.\r
+\r
+ http://www.OpenRTOS.com - Commercial support, development, porting,\r
+ licensing and training services.\r
+*/\r
+\r
+/*\r
+ * This file defines one of the more complex set of demo/test tasks. They are\r
+ * designed to stress test the queue implementation though pseudo simultaneous\r
+ * multiple reads and multiple writes from both tasks of varying priority and\r
+ * interrupts. The interrupts are prioritised such to ensure that nesting\r
+ * occurs (for those ports that support it).\r
+ *\r
+ * The test ensures that, while being accessed from three tasks and two\r
+ * interrupts, all the data sent to the queues is also received from\r
+ * the same queue, and that no duplicate items are either sent or received.\r
+ * The tests also ensure that a low priority task is never able to successfully\r
+ * read from or write to a queue when a task of higher priority is attempting\r
+ * the same operation.\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <string.h>\r
+\r
+/* SafeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "queue.h"\r
+#include "task.h"\r
+\r
+/* Demo app includes. */\r
+#include "IntQueue.h"\r
+#include "IntQueueTimer.h"\r
+\r
+/* Priorities used by test tasks. */\r
+#ifndef intqHIGHER_PRIORITY\r
+ #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )\r
+#endif\r
+#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )\r
+\r
+/* The number of values to send/receive before checking that all values were\r
+processed as expected. */\r
+#define intqNUM_VALUES_TO_LOG ( 200 )\r
+#define intqSHORT_DELAY ( 75 )\r
+\r
+/* The value by which the value being sent to or received from a queue should\r
+increment past intqNUM_VALUES_TO_LOG before we check that all values have been\r
+sent/received correctly. This is done to ensure that all tasks and interrupts\r
+accessing the queue have completed their accesses with the\r
+intqNUM_VALUES_TO_LOG range. */\r
+#define intqVALUE_OVERRUN ( 50 )\r
+\r
+/* The delay used by the polling task. A short delay is used for code\r
+coverage. */\r
+#define intqONE_TICK_DELAY ( 1 )\r
+\r
+/* Each task and interrupt is given a unique identifier. This value is used to\r
+identify which task sent or received each value. The identifier is also used\r
+to distinguish between two tasks that are running the same task function. */\r
+#define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )\r
+#define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )\r
+#define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )\r
+#define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )\r
+#define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )\r
+#define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )\r
+\r
+/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received\r
+from each queue by each task, otherwise an error is detected. */\r
+#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )\r
+\r
+/* Send the next value to the queue that is normally empty. This is called\r
+from within the interrupts. */\r
+#define timerNORMALLY_EMPTY_TX() \\r
+ if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \\r
+ { \\r
+ unsigned portBASE_TYPE uxSavedInterruptStatus; \\r
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \\r
+ { \\r
+ uxValueForNormallyEmptyQueue++; \\r
+ xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \\r
+ } \\r
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \\r
+ } \\r
+\r
+/* Send the next value to the queue that is normally full. This is called\r
+from within the interrupts. */\r
+#define timerNORMALLY_FULL_TX() \\r
+ if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \\r
+ { \\r
+ unsigned portBASE_TYPE uxSavedInterruptStatus; \\r
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \\r
+ { \\r
+ uxValueForNormallyFullQueue++; \\r
+ xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \\r
+ } \\r
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \\r
+ } \\r
+\r
+/* Receive a value from the normally empty queue. This is called from within\r
+an interrupt. */\r
+#define timerNORMALLY_EMPTY_RX() \\r
+ if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \\r
+ { \\r
+ prvQueueAccessLogError( __LINE__ ); \\r
+ } \\r
+ else \\r
+ { \\r
+ prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \\r
+ }\r
+\r
+/* Receive a value from the normally full queue. This is called from within\r
+an interrupt. */\r
+#define timerNORMALLY_FULL_RX() \\r
+ if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \\r
+ { \\r
+ prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \\r
+ } \\r
+\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The two queues used by the test. */\r
+static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;\r
+\r
+/* Variables used to detect a stall in one of the tasks. */\r
+static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;\r
+\r
+/* Any unexpected behaviour sets xErrorStatus to fail and log the line that\r
+caused the error in xErrorLine. */\r
+static portBASE_TYPE xErrorStatus = pdPASS;\r
+static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;\r
+\r
+/* Used for sequencing between tasks. */\r
+static portBASE_TYPE xWasSuspended = pdFALSE;\r
+\r
+/* The values that are sent to the queues. An incremented value is sent each\r
+time to each queue. */\r
+volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;\r
+\r
+/* A handle to some of the tasks is required so they can be suspended/resumed. */\r
+xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;\r
+\r
+/* When a value is received in a queue the value is ticked off in the array\r
+the array position of the value is set to a the identifier of the task or\r
+interrupt that accessed the queue. This way missing or duplicate values can be\r
+detected. */\r
+static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
+static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
+\r
+/* The test tasks themselves. */\r
+static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );\r
+static void prvLowerPriorityNormallyFullTask( void *pvParameters );\r
+static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );\r
+static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );\r
+static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );\r
+\r
+/* Used to mark the positions within the ucNormallyEmptyReceivedValues and\r
+ucNormallyFullReceivedValues arrays, while checking for duplicates. */\r
+static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );\r
+static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );\r
+\r
+/* Logs the line on which an error occurred. */\r
+static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartInterruptQueueTasks( void )\r
+{\r
+ /* Start the test tasks. */\r
+ xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );\r
+ xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );\r
+ xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "LQRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
+ xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );\r
+ xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );\r
+ xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "LQRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
+\r
+ /* Create the queues that are accessed by multiple tasks and multiple\r
+ interrupts. */\r
+ xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
+ xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
+\r
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
+ in use. The queue registry is provided as a means for kernel aware\r
+ debuggers to locate queues and has no purpose if a kernel aware debugger\r
+ is not being used. The call to vQueueAddToRegistry() will be removed\r
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
+ defined to be less than 1. */\r
+ vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );\r
+ vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )\r
+{\r
+ if( uxValue < intqNUM_VALUES_TO_LOG )\r
+ {\r
+ /* We don't expect to receive the same value twice, so if the value\r
+ has already been marked as received an error has occurred. */\r
+ if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Log that this value has been received. */\r
+ ucNormallyFullReceivedValues[ uxValue ] = uxSource;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )\r
+{\r
+ if( uxValue < intqNUM_VALUES_TO_LOG )\r
+ {\r
+ /* We don't expect to receive the same value twice, so if the value\r
+ has already been marked as received an error has occurred. */\r
+ if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Log that this value has been received. */\r
+ ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )\r
+{\r
+ /* Latch the line number that caused the error. */\r
+ xErrorLine = uxLine;\r
+ xErrorStatus = pdFAIL;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )\r
+{\r
+unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;\r
+\r
+ /* The timer should not be started until after the scheduler has started.\r
+ More than one task is running this code so we check the parameter value\r
+ to determine which task should start the timer. */\r
+ if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
+ {\r
+ vInitialiseTimerForIntQueueTest();\r
+ }\r
+\r
+ for( ;; )\r
+ {\r
+ /* Block waiting to receive a value from the normally empty queue.\r
+ Interrupts will write to the queue so we should receive a value. */\r
+ if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ else\r
+ {\r
+ /* Note which value was received so we can check all expected\r
+ values are received and no values are duplicated. */\r
+ prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );\r
+ }\r
+\r
+ /* Ensure the other task running this code gets a chance to execute. */\r
+ taskYIELD();\r
+\r
+ if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
+ {\r
+ /* Have we received all the expected values? */\r
+ if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
+ {\r
+ vTaskSuspend( xHighPriorityNormallyEmptyTask2 );\r
+\r
+ uxTask1 = 0;\r
+ uxTask2 = 0;\r
+ uxInterrupts = 0;\r
+\r
+ /* Loop through the array, checking that both tasks have\r
+ placed values into the array, and that no values are missing.\r
+ Start at 1 as we expect position 0 to be unused. */\r
+ for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
+ {\r
+ if( ucNormallyEmptyReceivedValues[ ux ] == 0 )\r
+ {\r
+ /* A value is missing. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ else\r
+ {\r
+ if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )\r
+ {\r
+ /* Value was placed into the array by task 1. */\r
+ uxTask1++;\r
+ }\r
+ else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )\r
+ {\r
+ /* Value was placed into the array by task 2. */\r
+ uxTask2++;\r
+ }\r
+ else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
+ {\r
+ uxInterrupts++;\r
+ }\r
+ }\r
+ }\r
+\r
+ if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )\r
+ {\r
+ /* Only task 2 seemed to log any values. */\r
+ uxErrorCount1++;\r
+ if( uxErrorCount1 > 2 )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uxErrorCount1 = 0;\r
+ }\r
+\r
+ if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )\r
+ {\r
+ /* Only task 1 seemed to log any values. */\r
+ uxErrorCount2++;\r
+ if( uxErrorCount2 > 2 )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uxErrorCount2 = 0;\r
+ }\r
+\r
+ if( uxInterrupts == 0 )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Clear the array again, ready to start a new cycle. */\r
+ memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );\r
+\r
+ uxHighPriorityLoops1++;\r
+ uxValueForNormallyEmptyQueue = 0;\r
+\r
+ /* Suspend ourselves, allowing the lower priority task to\r
+ actually receive something from the queue. Until now it\r
+ will have been prevented from doing so by the higher\r
+ priority tasks. The lower priority task will resume us\r
+ if it receives something. We will then resume the other\r
+ higher priority task. */\r
+ vTaskSuspend( NULL );\r
+ vTaskResume( xHighPriorityNormallyEmptyTask2 );\r
+ }\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )\r
+{\r
+unsigned portBASE_TYPE uxValue, uxRxed;\r
+\r
+ /* The parameters are not being used so avoid compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )\r
+ {\r
+ /* We should only obtain a value when the high priority task is\r
+ suspended. */\r
+ if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );\r
+\r
+ /* Wake the higher priority task again. */\r
+ vTaskResume( xHighPriorityNormallyEmptyTask1 );\r
+ uxLowPriorityLoops1++;\r
+ }\r
+ else\r
+ {\r
+ /* Raise our priority while we send so we can preempt the higher\r
+ priority task, and ensure we get the Tx value into the queue. */\r
+ vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
+\r
+ portENTER_CRITICAL();\r
+ {\r
+ uxValueForNormallyEmptyQueue++;\r
+ uxValue = uxValueForNormallyEmptyQueue;\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )\r
+{\r
+unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;\r
+\r
+ /* The parameters are not being used so avoid compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Make sure the queue starts full or near full. >> 1 as there are two\r
+ high priority tasks. */\r
+ for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
+ {\r
+ portENTER_CRITICAL();\r
+ {\r
+ uxValueForNormallyFullQueue++;\r
+ uxValueToTx = uxValueForNormallyFullQueue;\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
+ }\r
+\r
+ for( ;; )\r
+ {\r
+ portENTER_CRITICAL();\r
+ {\r
+ uxValueForNormallyFullQueue++;\r
+ uxValueToTx = uxValueForNormallyFullQueue;\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
+ {\r
+ /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not\r
+ expect it to ever time out. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Allow the other task running this code to run. */\r
+ taskYIELD();\r
+\r
+ /* Have all the expected values been sent to the queue? */\r
+ if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
+ {\r
+ /* Make sure the other high priority task completes its send of\r
+ any values below intqNUM_VALUE_TO_LOG. */\r
+ vTaskDelay( intqSHORT_DELAY );\r
+\r
+ vTaskSuspend( xHighPriorityNormallyFullTask2 );\r
+\r
+ if( xWasSuspended == pdTRUE )\r
+ {\r
+ /* We would have expected the other high priority task to have\r
+ set this back to false by now. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Set the suspended flag so an error is not logged if the other\r
+ task recognises a time out when it is unsuspended. */\r
+ xWasSuspended = pdTRUE;\r
+\r
+ /* Check interrupts are also sending. */\r
+ uxInterrupts = 0U;\r
+\r
+ /* Start at 1 as we expect position 0 to be unused. */\r
+ for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
+ {\r
+ if( ucNormallyFullReceivedValues[ ux ] == 0 )\r
+ {\r
+ /* A value was missing. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
+ {\r
+ uxInterrupts++;\r
+ }\r
+ }\r
+\r
+ if( uxInterrupts == 0 )\r
+ {\r
+ /* No writes from interrupts were found. Are interrupts\r
+ actually running? */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ /* Reset the array ready for the next cycle. */\r
+ memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );\r
+\r
+ uxHighPriorityLoops2++;\r
+ uxValueForNormallyFullQueue = 0;\r
+\r
+ /* Suspend ourselves, allowing the lower priority task to\r
+ actually receive something from the queue. Until now it\r
+ will have been prevented from doing so by the higher\r
+ priority tasks. The lower priority task will resume us\r
+ if it receives something. We will then resume the other\r
+ higher priority task. */\r
+ vTaskSuspend( NULL );\r
+ vTaskResume( xHighPriorityNormallyFullTask2 );\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )\r
+{\r
+unsigned portBASE_TYPE uxValueToTx, ux;\r
+\r
+ /* The parameters are not being used so avoid compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Make sure the queue starts full or near full. >> 1 as there are two\r
+ high priority tasks. */\r
+ for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
+ {\r
+ portENTER_CRITICAL();\r
+ {\r
+ uxValueForNormallyFullQueue++;\r
+ uxValueToTx = uxValueForNormallyFullQueue;\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
+ }\r
+\r
+ for( ;; )\r
+ {\r
+ portENTER_CRITICAL();\r
+ {\r
+ uxValueForNormallyFullQueue++;\r
+ uxValueToTx = uxValueForNormallyFullQueue;\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
+ {\r
+ if( xWasSuspended != pdTRUE )\r
+ {\r
+ /* It is ok to time out if the task has been suspended. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ }\r
+\r
+ xWasSuspended = pdFALSE;\r
+\r
+ taskYIELD();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvLowerPriorityNormallyFullTask( void *pvParameters )\r
+{\r
+unsigned portBASE_TYPE uxValue, uxTxed = 9999;\r
+\r
+ /* The parameters are not being used so avoid compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )\r
+ {\r
+ /* We would only expect to succeed when the higher priority task\r
+ is suspended. */\r
+ if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ vTaskResume( xHighPriorityNormallyFullTask1 );\r
+ uxLowPriorityLoops2++;\r
+ }\r
+ else\r
+ {\r
+ /* Raise our priority while we receive so we can preempt the higher\r
+ priority task, and ensure we get the value from the queue. */\r
+ vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
+\r
+ if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+ else\r
+ {\r
+ prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );\r
+ }\r
+\r
+ vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+portBASE_TYPE xFirstTimerHandler( void )\r
+{\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;\r
+static unsigned portBASE_TYPE uxNextOperation = 0;\r
+\r
+ /* Called from a timer interrupt. Perform various read and write\r
+ accesses on the queues. */\r
+\r
+ uxNextOperation++;\r
+\r
+ if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )\r
+ {\r
+ timerNORMALLY_EMPTY_TX();\r
+ timerNORMALLY_EMPTY_TX();\r
+ timerNORMALLY_EMPTY_TX();\r
+ }\r
+ else\r
+ {\r
+ timerNORMALLY_FULL_RX();\r
+ timerNORMALLY_FULL_RX();\r
+ timerNORMALLY_FULL_RX();\r
+ }\r
+\r
+ return xHigherPriorityTaskWoken;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+portBASE_TYPE xSecondTimerHandler( void )\r
+{\r
+unsigned portBASE_TYPE uxRxedValue;\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
+static unsigned portBASE_TYPE uxNextOperation = 0;\r
+\r
+ /* Called from a timer interrupt. Perform various read and write\r
+ accesses on the queues. */\r
+\r
+ uxNextOperation++;\r
+\r
+ if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )\r
+ {\r
+ timerNORMALLY_EMPTY_TX();\r
+ timerNORMALLY_EMPTY_TX();\r
+\r
+ timerNORMALLY_EMPTY_RX();\r
+ timerNORMALLY_EMPTY_RX();\r
+ }\r
+ else\r
+ {\r
+ timerNORMALLY_FULL_RX();\r
+ timerNORMALLY_FULL_TX();\r
+ timerNORMALLY_FULL_TX();\r
+ timerNORMALLY_FULL_TX();\r
+ timerNORMALLY_FULL_TX();\r
+ }\r
+\r
+ return xHigherPriorityTaskWoken;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+\r
+portBASE_TYPE xAreIntQueueTasksStillRunning( void )\r
+{\r
+static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;\r
+\r
+ /* xErrorStatus can be set outside of this function. This function just\r
+ checks that all the tasks are still cycling. */\r
+\r
+ if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )\r
+ {\r
+ /* The high priority 1 task has stalled. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ uxLastHighPriorityLoops1 = uxHighPriorityLoops1;\r
+\r
+ if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )\r
+ {\r
+ /* The high priority 2 task has stalled. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ uxLastHighPriorityLoops2 = uxHighPriorityLoops2;\r
+\r
+ if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )\r
+ {\r
+ /* The low priority 1 task has stalled. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ uxLastLowPriorityLoops1 = uxLowPriorityLoops1;\r
+\r
+ if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )\r
+ {\r
+ /* The low priority 2 task has stalled. */\r
+ prvQueueAccessLogError( __LINE__ );\r
+ }\r
+\r
+ uxLastLowPriorityLoops2 = uxLowPriorityLoops2;\r
+\r
+ return xErrorStatus;\r
+}\r
+\r