| /* | |
| FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. | |
| All rights reserved | |
| VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
| *************************************************************************** | |
| * * | |
| * FreeRTOS provides completely free yet professionally developed, * | |
| * robust, strictly quality controlled, supported, and cross * | |
| * platform software that has become a de facto standard. * | |
| * * | |
| * Help yourself get started quickly and support the FreeRTOS * | |
| * project by purchasing a FreeRTOS tutorial book, reference * | |
| * manual, or both from: http://www.FreeRTOS.org/Documentation * | |
| * * | |
| * Thank you! * | |
| * * | |
| *************************************************************************** | |
| 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. Full license text is available from the following | |
| link: http://www.freertos.org/a00114.html | |
| 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, books, training, latest versions, | |
| license and Real Time Engineers Ltd. contact details. | |
| http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
| including FreeRTOS+Trace - an indispensable productivity tool, a DOS | |
| compatible FAT file system, and our tiny thread aware UDP/IP stack. | |
| http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High | |
| Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS | |
| licenses offer ticketed support, indemnification and middleware. | |
| http://www.SafeRTOS.com - High Integrity Systems also provide a safety | |
| engineered and independently SIL3 certified version for use in safety and | |
| mission critical applications that require provable dependability. | |
| 1 tab == 4 spaces! | |
| */ | |
| /* | |
| * This file defines one of the more complex set of demo/test tasks. They are | |
| * designed to stress test the queue implementation though pseudo simultaneous | |
| * multiple reads and multiple writes from both tasks of varying priority and | |
| * interrupts. The interrupts are prioritised such to ensure that nesting | |
| * occurs (for those ports that support it). | |
| * | |
| * The test ensures that, while being accessed from three tasks and two | |
| * interrupts, all the data sent to the queues is also received from | |
| * the same queue, and that no duplicate items are either sent or received. | |
| * The tests also ensure that a low priority task is never able to successfully | |
| * read from or write to a queue when a task of higher priority is attempting | |
| * the same operation. | |
| */ | |
| /* Standard includes. */ | |
| #include <string.h> | |
| /* SafeRTOS includes. */ | |
| #include "FreeRTOS.h" | |
| #include "queue.h" | |
| #include "task.h" | |
| /* Demo app includes. */ | |
| #include "IntQueue.h" | |
| #include "IntQueueTimer.h" | |
| #if( INCLUDE_eTaskGetState != 1 ) | |
| #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file. | |
| #endif | |
| /* Priorities used by test tasks. */ | |
| #ifndef intqHIGHER_PRIORITY | |
| #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 ) | |
| #endif | |
| #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY ) | |
| /* The number of values to send/receive before checking that all values were | |
| processed as expected. */ | |
| #define intqNUM_VALUES_TO_LOG ( 200 ) | |
| #define intqSHORT_DELAY ( 140 ) | |
| /* The value by which the value being sent to or received from a queue should | |
| increment past intqNUM_VALUES_TO_LOG before we check that all values have been | |
| sent/received correctly. This is done to ensure that all tasks and interrupts | |
| accessing the queue have completed their accesses with the | |
| intqNUM_VALUES_TO_LOG range. */ | |
| #define intqVALUE_OVERRUN ( 50 ) | |
| /* The delay used by the polling task. A short delay is used for code | |
| coverage. */ | |
| #define intqONE_TICK_DELAY ( 1 ) | |
| /* Each task and interrupt is given a unique identifier. This value is used to | |
| identify which task sent or received each value. The identifier is also used | |
| to distinguish between two tasks that are running the same task function. */ | |
| #define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 ) | |
| #define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 ) | |
| #define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 ) | |
| #define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 ) | |
| #define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 ) | |
| #define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 ) | |
| /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received | |
| from each queue by each task, otherwise an error is detected. */ | |
| #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 ) | |
| /* Send the next value to the queue that is normally empty. This is called | |
| from within the interrupts. */ | |
| #define timerNORMALLY_EMPTY_TX() \ | |
| if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \ | |
| { \ | |
| unsigned portBASE_TYPE uxSavedInterruptStatus; \ | |
| uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \ | |
| { \ | |
| uxValueForNormallyEmptyQueue++; \ | |
| xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \ | |
| } \ | |
| portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ | |
| } \ | |
| /* Send the next value to the queue that is normally full. This is called | |
| from within the interrupts. */ | |
| #define timerNORMALLY_FULL_TX() \ | |
| if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \ | |
| { \ | |
| unsigned portBASE_TYPE uxSavedInterruptStatus; \ | |
| uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \ | |
| { \ | |
| uxValueForNormallyFullQueue++; \ | |
| xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \ | |
| } \ | |
| portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ | |
| } \ | |
| /* Receive a value from the normally empty queue. This is called from within | |
| an interrupt. */ | |
| #define timerNORMALLY_EMPTY_RX() \ | |
| if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \ | |
| { \ | |
| prvQueueAccessLogError( __LINE__ ); \ | |
| } \ | |
| else \ | |
| { \ | |
| prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \ | |
| } | |
| /* Receive a value from the normally full queue. This is called from within | |
| an interrupt. */ | |
| #define timerNORMALLY_FULL_RX() \ | |
| if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \ | |
| { \ | |
| prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \ | |
| } \ | |
| /*-----------------------------------------------------------*/ | |
| /* The two queues used by the test. */ | |
| static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue; | |
| /* Variables used to detect a stall in one of the tasks. */ | |
| static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0; | |
| /* Any unexpected behaviour sets xErrorStatus to fail and log the line that | |
| caused the error in xErrorLine. */ | |
| static portBASE_TYPE xErrorStatus = pdPASS; | |
| static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0; | |
| /* Used for sequencing between tasks. */ | |
| static portBASE_TYPE xWasSuspended = pdFALSE; | |
| /* The values that are sent to the queues. An incremented value is sent each | |
| time to each queue. */ | |
| volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0; | |
| /* A handle to some of the tasks is required so they can be suspended/resumed. */ | |
| TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2; | |
| /* When a value is received in a queue the value is ticked off in the array | |
| the array position of the value is set to a the identifier of the task or | |
| interrupt that accessed the queue. This way missing or duplicate values can be | |
| detected. */ | |
| static unsigned char ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 }; | |
| static unsigned char ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 }; | |
| /* The test tasks themselves. */ | |
| static void prvLowerPriorityNormallyEmptyTask( void *pvParameters ); | |
| static void prvLowerPriorityNormallyFullTask( void *pvParameters ); | |
| static void prvHigherPriorityNormallyEmptyTask( void *pvParameters ); | |
| static void prv1stHigherPriorityNormallyFullTask( void *pvParameters ); | |
| static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters ); | |
| /* Used to mark the positions within the ucNormallyEmptyReceivedValues and | |
| ucNormallyFullReceivedValues arrays, while checking for duplicates. */ | |
| static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource ); | |
| static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource ); | |
| /* Logs the line on which an error occurred. */ | |
| static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine ); | |
| /*-----------------------------------------------------------*/ | |
| void vStartInterruptQueueTasks( void ) | |
| { | |
| /* Start the test tasks. */ | |
| xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 ); | |
| xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 ); | |
| xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL ); | |
| xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 ); | |
| xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 ); | |
| xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL ); | |
| /* Create the queues that are accessed by multiple tasks and multiple | |
| interrupts. */ | |
| xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) ); | |
| xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) ); | |
| /* vQueueAddToRegistry() adds the queue to the queue registry, if one is | |
| in use. The queue registry is provided as a means for kernel aware | |
| debuggers to locate queues and has no purpose if a kernel aware debugger | |
| is not being used. The call to vQueueAddToRegistry() will be removed | |
| by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is | |
| defined to be less than 1. */ | |
| vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" ); | |
| vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" ); | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource ) | |
| { | |
| if( uxValue < intqNUM_VALUES_TO_LOG ) | |
| { | |
| /* We don't expect to receive the same value twice, so if the value | |
| has already been marked as received an error has occurred. */ | |
| if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Log that this value has been received. */ | |
| ucNormallyFullReceivedValues[ uxValue ] = uxSource; | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource ) | |
| { | |
| if( uxValue < intqNUM_VALUES_TO_LOG ) | |
| { | |
| /* We don't expect to receive the same value twice, so if the value | |
| has already been marked as received an error has occurred. */ | |
| if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Log that this value has been received. */ | |
| ucNormallyEmptyReceivedValues[ uxValue ] = uxSource; | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine ) | |
| { | |
| /* Latch the line number that caused the error. */ | |
| xErrorLine = uxLine; | |
| xErrorStatus = pdFAIL; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvHigherPriorityNormallyEmptyTask( void *pvParameters ) | |
| { | |
| unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0; | |
| /* The timer should not be started until after the scheduler has started. | |
| More than one task is running this code so we check the parameter value | |
| to determine which task should start the timer. */ | |
| if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 ) | |
| { | |
| vInitialiseTimerForIntQueueTest(); | |
| } | |
| for( ;; ) | |
| { | |
| /* Block waiting to receive a value from the normally empty queue. | |
| Interrupts will write to the queue so we should receive a value. */ | |
| if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| else | |
| { | |
| /* Note which value was received so we can check all expected | |
| values are received and no values are duplicated. */ | |
| prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters ); | |
| } | |
| /* Ensure the other task running this code gets a chance to execute. */ | |
| taskYIELD(); | |
| if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 ) | |
| { | |
| /* Have we received all the expected values? */ | |
| if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) ) | |
| { | |
| vTaskSuspend( xHighPriorityNormallyEmptyTask2 ); | |
| uxTask1 = 0; | |
| uxTask2 = 0; | |
| uxInterrupts = 0; | |
| /* Loop through the array, checking that both tasks have | |
| placed values into the array, and that no values are missing. | |
| Start at 1 as we expect position 0 to be unused. */ | |
| for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ ) | |
| { | |
| if( ucNormallyEmptyReceivedValues[ ux ] == 0 ) | |
| { | |
| /* A value is missing. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| else | |
| { | |
| if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 ) | |
| { | |
| /* Value was placed into the array by task 1. */ | |
| uxTask1++; | |
| } | |
| else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 ) | |
| { | |
| /* Value was placed into the array by task 2. */ | |
| uxTask2++; | |
| } | |
| else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT ) | |
| { | |
| uxInterrupts++; | |
| } | |
| } | |
| } | |
| if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT ) | |
| { | |
| /* Only task 2 seemed to log any values. */ | |
| uxErrorCount1++; | |
| if( uxErrorCount1 > 2 ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| } | |
| else | |
| { | |
| uxErrorCount1 = 0; | |
| } | |
| if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT ) | |
| { | |
| /* Only task 1 seemed to log any values. */ | |
| uxErrorCount2++; | |
| if( uxErrorCount2 > 2 ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| } | |
| else | |
| { | |
| uxErrorCount2 = 0; | |
| } | |
| if( uxInterrupts == 0 ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Clear the array again, ready to start a new cycle. */ | |
| memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) ); | |
| uxHighPriorityLoops1++; | |
| uxValueForNormallyEmptyQueue = 0; | |
| /* Suspend ourselves, allowing the lower priority task to | |
| actually receive something from the queue. Until now it | |
| will have been prevented from doing so by the higher | |
| priority tasks. The lower priority task will resume us | |
| if it receives something. We will then resume the other | |
| higher priority task. */ | |
| vTaskSuspend( NULL ); | |
| vTaskResume( xHighPriorityNormallyEmptyTask2 ); | |
| } | |
| } | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvLowerPriorityNormallyEmptyTask( void *pvParameters ) | |
| { | |
| unsigned portBASE_TYPE uxValue, uxRxed; | |
| /* The parameters are not being used so avoid compiler warnings. */ | |
| ( void ) pvParameters; | |
| for( ;; ) | |
| { | |
| if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY ) | |
| { | |
| /* A value should only be obtained when the high priority task is | |
| suspended. */ | |
| if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK ); | |
| /* Wake the higher priority task again. */ | |
| vTaskResume( xHighPriorityNormallyEmptyTask1 ); | |
| uxLowPriorityLoops1++; | |
| } | |
| else | |
| { | |
| /* Raise our priority while we send so we can preempt the higher | |
| priority task, and ensure we get the Tx value into the queue. */ | |
| vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 ); | |
| portENTER_CRITICAL(); | |
| { | |
| uxValueForNormallyEmptyQueue++; | |
| uxValue = uxValueForNormallyEmptyQueue; | |
| } | |
| portEXIT_CRITICAL(); | |
| if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| vTaskPrioritySet( NULL, intqLOWER_PRIORITY ); | |
| } | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prv1stHigherPriorityNormallyFullTask( void *pvParameters ) | |
| { | |
| unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts; | |
| /* The parameters are not being used so avoid compiler warnings. */ | |
| ( void ) pvParameters; | |
| /* Make sure the queue starts full or near full. >> 1 as there are two | |
| high priority tasks. */ | |
| for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ ) | |
| { | |
| portENTER_CRITICAL(); | |
| { | |
| uxValueForNormallyFullQueue++; | |
| uxValueToTx = uxValueForNormallyFullQueue; | |
| } | |
| portEXIT_CRITICAL(); | |
| xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ); | |
| } | |
| for( ;; ) | |
| { | |
| portENTER_CRITICAL(); | |
| { | |
| uxValueForNormallyFullQueue++; | |
| uxValueToTx = uxValueForNormallyFullQueue; | |
| } | |
| portEXIT_CRITICAL(); | |
| if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS ) | |
| { | |
| /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not | |
| expect it to ever time out. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Allow the other task running this code to run. */ | |
| taskYIELD(); | |
| /* Have all the expected values been sent to the queue? */ | |
| if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) ) | |
| { | |
| /* Make sure the other high priority task completes its send of | |
| any values below intqNUM_VALUE_TO_LOG. */ | |
| vTaskDelay( intqSHORT_DELAY ); | |
| vTaskSuspend( xHighPriorityNormallyFullTask2 ); | |
| if( xWasSuspended == pdTRUE ) | |
| { | |
| /* We would have expected the other high priority task to have | |
| set this back to false by now. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Set the suspended flag so an error is not logged if the other | |
| task recognises a time out when it is unsuspended. */ | |
| xWasSuspended = pdTRUE; | |
| /* Check interrupts are also sending. */ | |
| uxInterrupts = 0U; | |
| /* Start at 1 as we expect position 0 to be unused. */ | |
| for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ ) | |
| { | |
| if( ucNormallyFullReceivedValues[ ux ] == 0 ) | |
| { | |
| /* A value was missing. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT ) | |
| { | |
| uxInterrupts++; | |
| } | |
| } | |
| if( uxInterrupts == 0 ) | |
| { | |
| /* No writes from interrupts were found. Are interrupts | |
| actually running? */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| /* Reset the array ready for the next cycle. */ | |
| memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) ); | |
| uxHighPriorityLoops2++; | |
| uxValueForNormallyFullQueue = 0; | |
| /* Suspend ourselves, allowing the lower priority task to | |
| actually receive something from the queue. Until now it | |
| will have been prevented from doing so by the higher | |
| priority tasks. The lower priority task will resume us | |
| if it receives something. We will then resume the other | |
| higher priority task. */ | |
| vTaskSuspend( NULL ); | |
| vTaskResume( xHighPriorityNormallyFullTask2 ); | |
| } | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters ) | |
| { | |
| unsigned portBASE_TYPE uxValueToTx, ux; | |
| /* The parameters are not being used so avoid compiler warnings. */ | |
| ( void ) pvParameters; | |
| /* Make sure the queue starts full or near full. >> 1 as there are two | |
| high priority tasks. */ | |
| for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ ) | |
| { | |
| portENTER_CRITICAL(); | |
| { | |
| uxValueForNormallyFullQueue++; | |
| uxValueToTx = uxValueForNormallyFullQueue; | |
| } | |
| portEXIT_CRITICAL(); | |
| xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ); | |
| } | |
| for( ;; ) | |
| { | |
| portENTER_CRITICAL(); | |
| { | |
| uxValueForNormallyFullQueue++; | |
| uxValueToTx = uxValueForNormallyFullQueue; | |
| } | |
| portEXIT_CRITICAL(); | |
| if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS ) | |
| { | |
| if( xWasSuspended != pdTRUE ) | |
| { | |
| /* It is ok to time out if the task has been suspended. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| } | |
| xWasSuspended = pdFALSE; | |
| taskYIELD(); | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvLowerPriorityNormallyFullTask( void *pvParameters ) | |
| { | |
| unsigned portBASE_TYPE uxValue, uxTxed = 9999; | |
| /* The parameters are not being used so avoid compiler warnings. */ | |
| ( void ) pvParameters; | |
| for( ;; ) | |
| { | |
| if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL ) | |
| { | |
| /* Should only succeed when the higher priority task is suspended */ | |
| if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| vTaskResume( xHighPriorityNormallyFullTask1 ); | |
| uxLowPriorityLoops2++; | |
| } | |
| else | |
| { | |
| /* Raise our priority while we receive so we can preempt the higher | |
| priority task, and ensure we get the value from the queue. */ | |
| vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 ); | |
| if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS ) | |
| { | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| else | |
| { | |
| prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK ); | |
| } | |
| vTaskPrioritySet( NULL, intqLOWER_PRIORITY ); | |
| } | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| portBASE_TYPE xFirstTimerHandler( void ) | |
| { | |
| portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue; | |
| static unsigned portBASE_TYPE uxNextOperation = 0; | |
| /* Called from a timer interrupt. Perform various read and write | |
| accesses on the queues. */ | |
| uxNextOperation++; | |
| if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 ) | |
| { | |
| timerNORMALLY_EMPTY_TX(); | |
| timerNORMALLY_EMPTY_TX(); | |
| timerNORMALLY_EMPTY_TX(); | |
| } | |
| else | |
| { | |
| timerNORMALLY_FULL_RX(); | |
| timerNORMALLY_FULL_RX(); | |
| timerNORMALLY_FULL_RX(); | |
| } | |
| return xHigherPriorityTaskWoken; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| portBASE_TYPE xSecondTimerHandler( void ) | |
| { | |
| unsigned portBASE_TYPE uxRxedValue; | |
| portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; | |
| static unsigned portBASE_TYPE uxNextOperation = 0; | |
| /* Called from a timer interrupt. Perform various read and write | |
| accesses on the queues. */ | |
| uxNextOperation++; | |
| if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 ) | |
| { | |
| timerNORMALLY_EMPTY_TX(); | |
| timerNORMALLY_EMPTY_TX(); | |
| timerNORMALLY_EMPTY_RX(); | |
| timerNORMALLY_EMPTY_RX(); | |
| } | |
| else | |
| { | |
| timerNORMALLY_FULL_RX(); | |
| timerNORMALLY_FULL_TX(); | |
| timerNORMALLY_FULL_TX(); | |
| timerNORMALLY_FULL_TX(); | |
| timerNORMALLY_FULL_TX(); | |
| } | |
| return xHigherPriorityTaskWoken; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| portBASE_TYPE xAreIntQueueTasksStillRunning( void ) | |
| { | |
| static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0; | |
| /* xErrorStatus can be set outside of this function. This function just | |
| checks that all the tasks are still cycling. */ | |
| if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 ) | |
| { | |
| /* The high priority 1 task has stalled. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| uxLastHighPriorityLoops1 = uxHighPriorityLoops1; | |
| if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 ) | |
| { | |
| /* The high priority 2 task has stalled. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| uxLastHighPriorityLoops2 = uxHighPriorityLoops2; | |
| if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 ) | |
| { | |
| /* The low priority 1 task has stalled. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| uxLastLowPriorityLoops1 = uxLowPriorityLoops1; | |
| if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 ) | |
| { | |
| /* The low priority 2 task has stalled. */ | |
| prvQueueAccessLogError( __LINE__ ); | |
| } | |
| uxLastLowPriorityLoops2 = uxLowPriorityLoops2; | |
| return xErrorStatus; | |
| } | |