]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/IntQueue.c
Improve the error detection in some of the standard demo tasks.
[freertos] / FreeRTOS / Demo / Common / Minimal / IntQueue.c
1 /*\r
2     FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not it can be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
67     Integrity Systems, who sell the code with commercial support,\r
68     indemnification and middleware, under the OpenRTOS brand.\r
69 \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
71     engineered and independently SIL3 certified version for use in safety and\r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 /*\r
76  * This file defines one of the more complex set of demo/test tasks.  They are\r
77  * designed to stress test the queue implementation though pseudo simultaneous\r
78  * multiple reads and multiple writes from both tasks of varying priority and\r
79  * interrupts.  The interrupts are prioritised such to ensure that nesting\r
80  * occurs (for those ports that support it).\r
81  *\r
82  * The test ensures that, while being accessed from three tasks and two\r
83  * interrupts, all the data sent to the queues is also received from\r
84  * the same queue, and that no duplicate items are either sent or received.\r
85  * The tests also ensure that a low priority task is never able to successfully\r
86  * read from or write to a queue when a task of higher priority is attempting\r
87  * the same operation.\r
88  */\r
89 \r
90 /* Standard includes. */\r
91 #include <string.h>\r
92 \r
93 /* SafeRTOS includes. */\r
94 #include "FreeRTOS.h"\r
95 #include "queue.h"\r
96 #include "task.h"\r
97 \r
98 /* Demo app includes. */\r
99 #include "IntQueue.h"\r
100 #include "IntQueueTimer.h"\r
101 \r
102 /* Priorities used by test tasks. */\r
103 #ifndef intqHIGHER_PRIORITY\r
104         #define intqHIGHER_PRIORITY             ( configMAX_PRIORITIES - 2 )\r
105 #endif\r
106 #define intqLOWER_PRIORITY              ( tskIDLE_PRIORITY )\r
107 \r
108 /* The number of values to send/receive before checking that all values were\r
109 processed as expected. */\r
110 #define intqNUM_VALUES_TO_LOG   ( 200 )\r
111 #define intqSHORT_DELAY                 ( 140 )\r
112 \r
113 /* The value by which the value being sent to or received from a queue should\r
114 increment past intqNUM_VALUES_TO_LOG before we check that all values have been\r
115 sent/received correctly.  This is done to ensure that all tasks and interrupts\r
116 accessing the queue have completed their accesses with the\r
117 intqNUM_VALUES_TO_LOG range. */\r
118 #define intqVALUE_OVERRUN               ( 50 )\r
119 \r
120 /* The delay used by the polling task.  A short delay is used for code\r
121 coverage. */\r
122 #define intqONE_TICK_DELAY              ( 1 )\r
123 \r
124 /* Each task and interrupt is given a unique identifier.  This value is used to\r
125 identify which task sent or received each value.  The identifier is also used\r
126 to distinguish between two tasks that are running the same task function. */\r
127 #define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )\r
128 #define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )\r
129 #define intqLOW_PRIORITY_TASK   ( ( unsigned portBASE_TYPE ) 3 )\r
130 #define intqFIRST_INTERRUPT             ( ( unsigned portBASE_TYPE ) 4 )\r
131 #define intqSECOND_INTERRUPT    ( ( unsigned portBASE_TYPE ) 5 )\r
132 #define intqQUEUE_LENGTH                ( ( unsigned portBASE_TYPE ) 10 )\r
133 \r
134 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received\r
135 from each queue by each task, otherwise an error is detected. */\r
136 #define intqMIN_ACCEPTABLE_TASK_COUNT           ( 5 )\r
137 \r
138 /* Send the next value to the queue that is normally empty.  This is called\r
139 from within the interrupts. */\r
140 #define timerNORMALLY_EMPTY_TX()                                                                                                                                                                                        \\r
141         if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE )                                                                                                                 \\r
142         {                                                                                                                                                                                                                                               \\r
143         unsigned portBASE_TYPE uxSavedInterruptStatus;                                                                                                                                                  \\r
144                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \\r
145                 {                                                                                                                                                                                                                                       \\r
146                         uxValueForNormallyEmptyQueue++;                                                                                                                                                                 \\r
147                         xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken );  \\r
148                 }                                                                                                                                                                                                                                       \\r
149                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
150         }                                                                                                                                                                                                                                               \\r
151 \r
152 /* Send the next value to the queue that is normally full.  This is called\r
153 from within the interrupts. */\r
154 #define timerNORMALLY_FULL_TX()                                                                                                                                                                                         \\r
155         if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE )                                                                                                                  \\r
156         {                                                                                                                                                                                                                                               \\r
157         unsigned portBASE_TYPE uxSavedInterruptStatus;                                                                                                                                                  \\r
158                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \\r
159                 {                                                                                                                                                                                                                                       \\r
160                         uxValueForNormallyFullQueue++;                                                                                                                                                                  \\r
161                         xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken );    \\r
162                 }                                                                                                                                                                                                                                       \\r
163                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
164         }                                                                                                                                                                                                                                               \\r
165 \r
166 /* Receive a value from the normally empty queue.  This is called from within\r
167 an interrupt. */\r
168 #define timerNORMALLY_EMPTY_RX()                                                                                                                                                        \\r
169         if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS )    \\r
170         {                                                                                                                                                                                                               \\r
171                 prvQueueAccessLogError( __LINE__ );                                                                                                                                     \\r
172         }                                                                                                                                                                                                               \\r
173         else                                                                                                                                                                                                    \\r
174         {                                                                                                                                                                                                               \\r
175                 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT );                                                                      \\r
176         }\r
177 \r
178 /* Receive a value from the normally full queue.  This is called from within\r
179 an interrupt. */\r
180 #define timerNORMALLY_FULL_RX()                                                                                                                                                         \\r
181         if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS )             \\r
182         {                                                                                                                                                                                                               \\r
183                 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT );                                                                       \\r
184         }                                                                                                                                                                                                               \\r
185 \r
186 \r
187 /*-----------------------------------------------------------*/\r
188 \r
189 /* The two queues used by the test. */\r
190 static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;\r
191 \r
192 /* Variables used to detect a stall in one of the tasks. */\r
193 static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;\r
194 \r
195 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that\r
196 caused the error in xErrorLine. */\r
197 static portBASE_TYPE xErrorStatus = pdPASS;\r
198 static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;\r
199 \r
200 /* Used for sequencing between tasks. */\r
201 static portBASE_TYPE xWasSuspended = pdFALSE;\r
202 \r
203 /* The values that are sent to the queues.  An incremented value is sent each\r
204 time to each queue. */\r
205 volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;\r
206 \r
207 /* A handle to some of the tasks is required so they can be suspended/resumed. */\r
208 xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;\r
209 \r
210 /* When a value is received in a queue the value is ticked off in the array\r
211 the array position of the value is set to a the identifier of the task or\r
212 interrupt that accessed the queue.  This way missing or duplicate values can be\r
213 detected. */\r
214 static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
215 static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
216 \r
217 /* The test tasks themselves. */\r
218 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );\r
219 static void prvLowerPriorityNormallyFullTask( void *pvParameters );\r
220 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );\r
221 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );\r
222 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );\r
223 \r
224 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and\r
225 ucNormallyFullReceivedValues arrays, while checking for duplicates. */\r
226 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );\r
227 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );\r
228 \r
229 /* Logs the line on which an error occurred. */\r
230 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );\r
231 \r
232 /*-----------------------------------------------------------*/\r
233 \r
234 void vStartInterruptQueueTasks( void )\r
235 {\r
236         /* Start the test tasks. */\r
237         xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );\r
238         xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );\r
239         xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
240         xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );\r
241         xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );\r
242         xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
243 \r
244         /* Create the queues that are accessed by multiple tasks and multiple\r
245         interrupts. */\r
246         xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
247         xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
248 //      vTraceSetQueueName( xNormallyFullQueue, "NF" );\r
249 //      vTraceSetQueueName( xNormallyEmptyQueue, "NE" );\r
250 \r
251         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
252         in use.  The queue registry is provided as a means for kernel aware\r
253         debuggers to locate queues and has no purpose if a kernel aware debugger\r
254         is not being used.  The call to vQueueAddToRegistry() will be removed\r
255         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
256         defined to be less than 1. */\r
257         vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );\r
258         vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );\r
259 }\r
260 /*-----------------------------------------------------------*/\r
261 \r
262 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )\r
263 {\r
264         if( uxValue < intqNUM_VALUES_TO_LOG )\r
265         {\r
266                 /* We don't expect to receive the same value twice, so if the value\r
267                 has already been marked as received an error has occurred. */\r
268                 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )\r
269                 {\r
270                         prvQueueAccessLogError( __LINE__ );\r
271                 }\r
272 \r
273                 /* Log that this value has been received. */\r
274                 ucNormallyFullReceivedValues[ uxValue ] = uxSource;\r
275         }\r
276 }\r
277 /*-----------------------------------------------------------*/\r
278 \r
279 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )\r
280 {\r
281         if( uxValue < intqNUM_VALUES_TO_LOG )\r
282         {\r
283                 /* We don't expect to receive the same value twice, so if the value\r
284                 has already been marked as received an error has occurred. */\r
285                 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )\r
286                 {\r
287                         prvQueueAccessLogError( __LINE__ );\r
288                 }\r
289 \r
290                 /* Log that this value has been received. */\r
291                 ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;\r
292         }\r
293 }\r
294 /*-----------------------------------------------------------*/\r
295 \r
296 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )\r
297 {\r
298         /* Latch the line number that caused the error. */\r
299         xErrorLine = uxLine;\r
300         xErrorStatus = pdFAIL;\r
301 }\r
302 /*-----------------------------------------------------------*/\r
303 \r
304 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )\r
305 {\r
306 unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;\r
307 \r
308         /* The timer should not be started until after the scheduler has started.\r
309         More than one task is running this code so we check the parameter value\r
310         to determine which task should start the timer. */\r
311         if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
312         {\r
313                 vInitialiseTimerForIntQueueTest();\r
314         }\r
315 \r
316         for( ;; )\r
317         {\r
318                 /* Block waiting to receive a value from the normally empty queue.\r
319                 Interrupts will write to the queue so we should receive a value. */\r
320                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )\r
321                 {\r
322                         prvQueueAccessLogError( __LINE__ );\r
323                 }\r
324                 else\r
325                 {\r
326                         /* Note which value was received so we can check all expected\r
327                         values are received and no values are duplicated. */\r
328                         prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );\r
329                 }\r
330 \r
331                 /* Ensure the other task running this code gets a chance to execute. */\r
332                 taskYIELD();\r
333 \r
334                 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
335                 {\r
336                         /* Have we received all the expected values? */\r
337                         if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
338                         {\r
339                                 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );\r
340 \r
341                                 uxTask1 = 0;\r
342                                 uxTask2 = 0;\r
343                                 uxInterrupts = 0;\r
344 \r
345                                 /* Loop through the array, checking that both tasks have\r
346                                 placed values into the array, and that no values are missing.\r
347                                 Start at 1 as we expect position 0 to be unused. */\r
348                                 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
349                                 {\r
350                                         if( ucNormallyEmptyReceivedValues[ ux ] == 0 )\r
351                                         {\r
352                                                 /* A value is missing. */\r
353                                                 prvQueueAccessLogError( __LINE__ );\r
354                                         }\r
355                                         else\r
356                                         {\r
357                                                 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )\r
358                                                 {\r
359                                                         /* Value was placed into the array by task 1. */\r
360                                                         uxTask1++;\r
361                                                 }\r
362                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )\r
363                                                 {\r
364                                                         /* Value was placed into the array by task 2. */\r
365                                                         uxTask2++;\r
366                                                 }\r
367                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
368                                                 {\r
369                                                         uxInterrupts++;\r
370                                                 }\r
371                                         }\r
372                                 }\r
373 \r
374                                 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )\r
375                                 {\r
376                                         /* Only task 2 seemed to log any values. */\r
377                                         uxErrorCount1++;\r
378                                         if( uxErrorCount1 > 2 )\r
379                                         {\r
380                                                 prvQueueAccessLogError( __LINE__ );\r
381                                         }\r
382                                 }\r
383                                 else\r
384                                 {\r
385                                         uxErrorCount1 = 0;\r
386                                 }\r
387 \r
388                                 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT  )\r
389                                 {\r
390                                         /* Only task 1 seemed to log any values. */\r
391                                         uxErrorCount2++;\r
392                                         if( uxErrorCount2 > 2 )\r
393                                         {\r
394                                                 prvQueueAccessLogError( __LINE__ );\r
395                                         }\r
396                                 }\r
397                                 else\r
398                                 {\r
399                                         uxErrorCount2 = 0;\r
400                                 }\r
401 \r
402                                 if( uxInterrupts == 0 )\r
403                                 {\r
404                                         prvQueueAccessLogError( __LINE__ );\r
405                                 }\r
406 \r
407                                 /* Clear the array again, ready to start a new cycle. */\r
408                                 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );\r
409 \r
410                                 uxHighPriorityLoops1++;\r
411                                 uxValueForNormallyEmptyQueue = 0;\r
412 \r
413                                 /* Suspend ourselves, allowing the lower priority task to\r
414                                 actually receive something from the queue.  Until now it\r
415                                 will have been prevented from doing so by the higher\r
416                                 priority tasks.  The lower priority task will resume us\r
417                                 if it receives something.  We will then resume the other\r
418                                 higher priority task. */\r
419                                 vTaskSuspend( NULL );\r
420                                 vTaskResume( xHighPriorityNormallyEmptyTask2 );\r
421                         }\r
422                 }\r
423         }\r
424 }\r
425 /*-----------------------------------------------------------*/\r
426 \r
427 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )\r
428 {\r
429 unsigned portBASE_TYPE uxValue, uxRxed;\r
430 \r
431         /* The parameters are not being used so avoid compiler warnings. */\r
432         ( void ) pvParameters;\r
433 \r
434         for( ;; )\r
435         {\r
436                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )\r
437                 {\r
438                         /* We should only obtain a value when the high priority task is\r
439                         suspended. */\r
440                         if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )\r
441                         {\r
442                                 prvQueueAccessLogError( __LINE__ );\r
443                         }\r
444 \r
445                         prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );\r
446 \r
447                         /* Wake the higher priority task again. */\r
448                         vTaskResume( xHighPriorityNormallyEmptyTask1 );\r
449                         uxLowPriorityLoops1++;\r
450                 }\r
451                 else\r
452                 {\r
453                         /* Raise our priority while we send so we can preempt the higher\r
454                         priority task, and ensure we get the Tx value into the queue. */\r
455                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
456 \r
457                         portENTER_CRITICAL();\r
458                         {\r
459                                 uxValueForNormallyEmptyQueue++;\r
460                                 uxValue = uxValueForNormallyEmptyQueue;\r
461                         }\r
462                         portEXIT_CRITICAL();\r
463 \r
464                         if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
465                         {\r
466                                 prvQueueAccessLogError( __LINE__ );\r
467                         }\r
468 \r
469                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
470                 }\r
471         }\r
472 }\r
473 /*-----------------------------------------------------------*/\r
474 \r
475 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )\r
476 {\r
477 unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;\r
478 \r
479         /* The parameters are not being used so avoid compiler warnings. */\r
480         ( void ) pvParameters;\r
481 \r
482         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
483         high priority tasks. */\r
484         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
485         {\r
486                 portENTER_CRITICAL();\r
487                 {\r
488                         uxValueForNormallyFullQueue++;\r
489                         uxValueToTx = uxValueForNormallyFullQueue;\r
490                 }\r
491                 portEXIT_CRITICAL();\r
492 \r
493                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
494         }\r
495 \r
496         for( ;; )\r
497         {\r
498                 portENTER_CRITICAL();\r
499                 {\r
500                         uxValueForNormallyFullQueue++;\r
501                         uxValueToTx = uxValueForNormallyFullQueue;\r
502                 }\r
503                 portEXIT_CRITICAL();\r
504 \r
505                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
506                 {\r
507                         /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not\r
508                         expect it to ever time out. */\r
509                         prvQueueAccessLogError( __LINE__ );\r
510                 }\r
511 \r
512                 /* Allow the other task running this code to run. */\r
513                 taskYIELD();\r
514 \r
515                 /* Have all the expected values been sent to the queue? */\r
516                 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
517                 {\r
518                         /* Make sure the other high priority task completes its send of\r
519                         any values below intqNUM_VALUE_TO_LOG. */\r
520                         vTaskDelay( intqSHORT_DELAY );\r
521 \r
522                         vTaskSuspend( xHighPriorityNormallyFullTask2 );\r
523 \r
524                         if( xWasSuspended == pdTRUE )\r
525                         {\r
526                                 /* We would have expected the other high priority task to have\r
527                                 set this back to false by now. */\r
528                                 prvQueueAccessLogError( __LINE__ );\r
529                         }\r
530 \r
531                         /* Set the suspended flag so an error is not logged if the other\r
532                         task recognises a time out when it is unsuspended. */\r
533                         xWasSuspended = pdTRUE;\r
534 \r
535                         /* Check interrupts are also sending. */\r
536                         uxInterrupts = 0U;\r
537 \r
538                         /* Start at 1 as we expect position 0 to be unused. */\r
539                         for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
540                         {\r
541                                 if( ucNormallyFullReceivedValues[ ux ] == 0 )\r
542                                 {\r
543                                         /* A value was missing. */\r
544                                         prvQueueAccessLogError( __LINE__ );\r
545                                 }\r
546                                 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
547                                 {\r
548                                         uxInterrupts++;\r
549                                 }\r
550                         }\r
551 \r
552                         if( uxInterrupts == 0 )\r
553                         {\r
554                                 /* No writes from interrupts were found.  Are interrupts\r
555                                 actually running? */\r
556                                 prvQueueAccessLogError( __LINE__ );\r
557                         }\r
558 \r
559                         /* Reset the array ready for the next cycle. */\r
560                         memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );\r
561 \r
562                         uxHighPriorityLoops2++;\r
563                         uxValueForNormallyFullQueue = 0;\r
564 \r
565                         /* Suspend ourselves, allowing the lower priority task to\r
566                         actually receive something from the queue.  Until now it\r
567                         will have been prevented from doing so by the higher\r
568                         priority tasks.  The lower priority task will resume us\r
569                         if it receives something.  We will then resume the other\r
570                         higher priority task. */\r
571                         vTaskSuspend( NULL );\r
572                         vTaskResume( xHighPriorityNormallyFullTask2 );\r
573                 }\r
574         }\r
575 }\r
576 /*-----------------------------------------------------------*/\r
577 \r
578 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )\r
579 {\r
580 unsigned portBASE_TYPE uxValueToTx, ux;\r
581 \r
582         /* The parameters are not being used so avoid compiler warnings. */\r
583         ( void ) pvParameters;\r
584 \r
585         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
586         high priority tasks. */\r
587         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
588         {\r
589                 portENTER_CRITICAL();\r
590                 {\r
591                         uxValueForNormallyFullQueue++;\r
592                         uxValueToTx = uxValueForNormallyFullQueue;\r
593                 }\r
594                 portEXIT_CRITICAL();\r
595 \r
596                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
597         }\r
598 \r
599         for( ;; )\r
600         {\r
601                 portENTER_CRITICAL();\r
602                 {\r
603                         uxValueForNormallyFullQueue++;\r
604                         uxValueToTx = uxValueForNormallyFullQueue;\r
605                 }\r
606                 portEXIT_CRITICAL();\r
607 \r
608                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
609                 {\r
610                         if( xWasSuspended != pdTRUE )\r
611                         {\r
612                                 /* It is ok to time out if the task has been suspended. */\r
613                                 prvQueueAccessLogError( __LINE__ );\r
614                         }\r
615                 }\r
616 \r
617                 xWasSuspended = pdFALSE;\r
618 \r
619                 taskYIELD();\r
620         }\r
621 }\r
622 /*-----------------------------------------------------------*/\r
623 \r
624 static void prvLowerPriorityNormallyFullTask( void *pvParameters )\r
625 {\r
626 unsigned portBASE_TYPE uxValue, uxTxed = 9999;\r
627 \r
628         /* The parameters are not being used so avoid compiler warnings. */\r
629         ( void ) pvParameters;\r
630 \r
631         for( ;; )\r
632         {\r
633                 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )\r
634                 {\r
635                         /* We would only expect to succeed when the higher priority task\r
636                         is suspended. */\r
637                         if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )\r
638                         {\r
639                                 prvQueueAccessLogError( __LINE__ );\r
640                         }\r
641 \r
642                         vTaskResume( xHighPriorityNormallyFullTask1 );\r
643                         uxLowPriorityLoops2++;\r
644                 }\r
645                 else\r
646                 {\r
647                         /* Raise our priority while we receive so we can preempt the higher\r
648                         priority task, and ensure we get the value from the queue. */\r
649                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
650 \r
651                         if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
652                         {\r
653                                 prvQueueAccessLogError( __LINE__ );\r
654                         }\r
655                         else\r
656                         {\r
657                                 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );\r
658                         }\r
659 \r
660                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
661                 }\r
662         }\r
663 }\r
664 /*-----------------------------------------------------------*/\r
665 \r
666 portBASE_TYPE xFirstTimerHandler( void )\r
667 {\r
668 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;\r
669 static unsigned portBASE_TYPE uxNextOperation = 0;\r
670 \r
671         /* Called from a timer interrupt.  Perform various read and write\r
672         accesses on the queues. */\r
673 \r
674         uxNextOperation++;\r
675 \r
676         if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )\r
677         {\r
678                 timerNORMALLY_EMPTY_TX();\r
679                 timerNORMALLY_EMPTY_TX();\r
680                 timerNORMALLY_EMPTY_TX();\r
681         }\r
682         else\r
683         {\r
684                 timerNORMALLY_FULL_RX();\r
685                 timerNORMALLY_FULL_RX();\r
686                 timerNORMALLY_FULL_RX();\r
687         }\r
688 \r
689         return xHigherPriorityTaskWoken;\r
690 }\r
691 /*-----------------------------------------------------------*/\r
692 \r
693 portBASE_TYPE xSecondTimerHandler( void )\r
694 {\r
695 unsigned portBASE_TYPE uxRxedValue;\r
696 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
697 static unsigned portBASE_TYPE uxNextOperation = 0;\r
698 \r
699         /* Called from a timer interrupt.  Perform various read and write\r
700         accesses on the queues. */\r
701 \r
702         uxNextOperation++;\r
703 \r
704         if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )\r
705         {\r
706                 timerNORMALLY_EMPTY_TX();\r
707                 timerNORMALLY_EMPTY_TX();\r
708 \r
709                 timerNORMALLY_EMPTY_RX();\r
710                 timerNORMALLY_EMPTY_RX();\r
711         }\r
712         else\r
713         {\r
714                 timerNORMALLY_FULL_RX();\r
715                 timerNORMALLY_FULL_TX();\r
716                 timerNORMALLY_FULL_TX();\r
717                 timerNORMALLY_FULL_TX();\r
718                 timerNORMALLY_FULL_TX();\r
719         }\r
720 \r
721         return xHigherPriorityTaskWoken;\r
722 }\r
723 /*-----------------------------------------------------------*/\r
724 \r
725 \r
726 portBASE_TYPE xAreIntQueueTasksStillRunning( void )\r
727 {\r
728 static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;\r
729 \r
730         /* xErrorStatus can be set outside of this function.  This function just\r
731         checks that all the tasks are still cycling. */\r
732 \r
733         if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )\r
734         {\r
735                 /* The high priority 1 task has stalled. */\r
736                 prvQueueAccessLogError( __LINE__ );\r
737         }\r
738 \r
739         uxLastHighPriorityLoops1 = uxHighPriorityLoops1;\r
740 \r
741         if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )\r
742         {\r
743                 /* The high priority 2 task has stalled. */\r
744                 prvQueueAccessLogError( __LINE__ );\r
745         }\r
746 \r
747         uxLastHighPriorityLoops2 = uxHighPriorityLoops2;\r
748 \r
749         if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )\r
750         {\r
751                 /* The low priority 1 task has stalled. */\r
752                 prvQueueAccessLogError( __LINE__ );\r
753         }\r
754 \r
755         uxLastLowPriorityLoops1 = uxLowPriorityLoops1;\r
756 \r
757         if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )\r
758         {\r
759                 /* The low priority 2 task has stalled. */\r
760                 prvQueueAccessLogError( __LINE__ );\r
761         }\r
762 \r
763         uxLastLowPriorityLoops2 = uxLowPriorityLoops2;\r
764 \r
765         return xErrorStatus;\r
766 }\r
767 \r