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