]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/IntQueue.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / Common / Minimal / IntQueue.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /*\r
30  * This file defines one of the more complex set of demo/test tasks.  They are\r
31  * designed to stress test the queue implementation though pseudo simultaneous\r
32  * multiple reads and multiple writes from both tasks of varying priority and\r
33  * interrupts.  The interrupts are prioritised such to ensure that nesting\r
34  * occurs (for those ports that support it).\r
35  *\r
36  * The test ensures that, while being accessed from three tasks and two\r
37  * interrupts, all the data sent to the queues is also received from\r
38  * the same queue, and that no duplicate items are either sent or received.\r
39  * The tests also ensure that a low priority task is never able to successfully\r
40  * read from or write to a queue when a task of higher priority is attempting\r
41  * the same operation.\r
42  */\r
43 \r
44 /* Standard includes. */\r
45 #include <string.h>\r
46 \r
47 /* SafeRTOS includes. */\r
48 #include "FreeRTOS.h"\r
49 #include "queue.h"\r
50 #include "task.h"\r
51 \r
52 /* Demo app includes. */\r
53 #include "IntQueue.h"\r
54 #include "IntQueueTimer.h"\r
55 \r
56 #if( INCLUDE_eTaskGetState != 1 )\r
57         #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.\r
58 #endif\r
59 \r
60 /* Priorities used by test tasks. */\r
61 #ifndef intqHIGHER_PRIORITY\r
62         #define intqHIGHER_PRIORITY             ( configMAX_PRIORITIES - 2 )\r
63 #endif\r
64 #define intqLOWER_PRIORITY              ( tskIDLE_PRIORITY )\r
65 \r
66 /* The number of values to send/receive before checking that all values were\r
67 processed as expected. */\r
68 #define intqNUM_VALUES_TO_LOG   ( 200 )\r
69 #define intqSHORT_DELAY                 ( 140 )\r
70 \r
71 /* The value by which the value being sent to or received from a queue should\r
72 increment past intqNUM_VALUES_TO_LOG before we check that all values have been\r
73 sent/received correctly.  This is done to ensure that all tasks and interrupts\r
74 accessing the queue have completed their accesses with the\r
75 intqNUM_VALUES_TO_LOG range. */\r
76 #define intqVALUE_OVERRUN               ( 50 )\r
77 \r
78 /* The delay used by the polling task.  A short delay is used for code\r
79 coverage. */\r
80 #define intqONE_TICK_DELAY              ( 1 )\r
81 \r
82 /* Each task and interrupt is given a unique identifier.  This value is used to\r
83 identify which task sent or received each value.  The identifier is also used\r
84 to distinguish between two tasks that are running the same task function. */\r
85 #define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )\r
86 #define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )\r
87 #define intqLOW_PRIORITY_TASK   ( ( UBaseType_t ) 3 )\r
88 #define intqFIRST_INTERRUPT             ( ( UBaseType_t ) 4 )\r
89 #define intqSECOND_INTERRUPT    ( ( UBaseType_t ) 5 )\r
90 #define intqQUEUE_LENGTH                ( ( UBaseType_t ) 10 )\r
91 \r
92 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received\r
93 from each queue by each task, otherwise an error is detected. */\r
94 #define intqMIN_ACCEPTABLE_TASK_COUNT           ( 5 )\r
95 \r
96 /* Send the next value to the queue that is normally empty.  This is called\r
97 from within the interrupts. */\r
98 #define timerNORMALLY_EMPTY_TX()                                                                                                                                                                                        \\r
99         if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE )                                                                                                                 \\r
100         {                                                                                                                                                                                                                                               \\r
101         UBaseType_t uxSavedInterruptStatus;                                                                                                                                                                             \\r
102                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \\r
103                 {                                                                                                                                                                                                                                       \\r
104                         uxValueForNormallyEmptyQueue++;                                                                                                                                                                 \\r
105                         if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \\r
106                         {                                                                                                                                                                                                                               \\r
107                                 uxValueForNormallyEmptyQueue--;                                                                                                                                                         \\r
108                         }                                                                                                                                                                                                                               \\r
109                 }                                                                                                                                                                                                                                       \\r
110                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
111         }                                                                                                                                                                                                                                               \\r
112 \r
113 /* Send the next value to the queue that is normally full.  This is called\r
114 from within the interrupts. */\r
115 #define timerNORMALLY_FULL_TX()                                                                                                                                                                                         \\r
116         if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE )                                                                                                                  \\r
117         {                                                                                                                                                                                                                                               \\r
118         UBaseType_t uxSavedInterruptStatus;                                                                                                                                                                             \\r
119                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \\r
120                 {                                                                                                                                                                                                                                       \\r
121                         uxValueForNormallyFullQueue++;                                                                                                                                                                  \\r
122                         if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \\r
123                         {                                                                                                                                                                                                                               \\r
124                                 uxValueForNormallyFullQueue--;                                                                                                                                                          \\r
125                         }                                                                                                                                                                                                                               \\r
126                 }                                                                                                                                                                                                                                       \\r
127                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
128         }                                                                                                                                                                                                                                               \\r
129 \r
130 /* Receive a value from the normally empty queue.  This is called from within\r
131 an interrupt. */\r
132 #define timerNORMALLY_EMPTY_RX()                                                                                                                                                        \\r
133         if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS )    \\r
134         {                                                                                                                                                                                                               \\r
135                 prvQueueAccessLogError( __LINE__ );                                                                                                                                     \\r
136         }                                                                                                                                                                                                               \\r
137         else                                                                                                                                                                                                    \\r
138         {                                                                                                                                                                                                               \\r
139                 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT );                                                                      \\r
140         }\r
141 \r
142 /* Receive a value from the normally full queue.  This is called from within\r
143 an interrupt. */\r
144 #define timerNORMALLY_FULL_RX()                                                                                                                                                         \\r
145         if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS )             \\r
146         {                                                                                                                                                                                                               \\r
147                 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT );                                                                       \\r
148         }                                                                                                                                                                                                               \\r
149 \r
150 \r
151 /*-----------------------------------------------------------*/\r
152 \r
153 /* The two queues used by the test. */\r
154 static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;\r
155 \r
156 /* Variables used to detect a stall in one of the tasks. */\r
157 static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;\r
158 \r
159 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that\r
160 caused the error in xErrorLine. */\r
161 static BaseType_t xErrorStatus = pdPASS;\r
162 static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;\r
163 \r
164 /* Used for sequencing between tasks. */\r
165 static BaseType_t xWasSuspended = pdFALSE;\r
166 \r
167 /* The values that are sent to the queues.  An incremented value is sent each\r
168 time to each queue. */\r
169 static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;\r
170 \r
171 /* A handle to some of the tasks is required so they can be suspended/resumed. */\r
172 TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;\r
173 \r
174 /* When a value is received in a queue the value is ticked off in the array\r
175 the array position of the value is set to a the identifier of the task or\r
176 interrupt that accessed the queue.  This way missing or duplicate values can be\r
177 detected. */\r
178 static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
179 static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
180 \r
181 /* The test tasks themselves. */\r
182 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );\r
183 static void prvLowerPriorityNormallyFullTask( void *pvParameters );\r
184 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );\r
185 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );\r
186 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );\r
187 \r
188 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and\r
189 ucNormallyFullReceivedValues arrays, while checking for duplicates. */\r
190 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource );\r
191 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource );\r
192 \r
193 /* Logs the line on which an error occurred. */\r
194 static void prvQueueAccessLogError( UBaseType_t uxLine );\r
195 \r
196 /*-----------------------------------------------------------*/\r
197 \r
198 void vStartInterruptQueueTasks( void )\r
199 {\r
200         /* Start the test tasks. */\r
201         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );\r
202         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );\r
203         xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
204         xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );\r
205         xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );\r
206         xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
207 \r
208         /* Create the queues that are accessed by multiple tasks and multiple\r
209         interrupts. */\r
210         xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );\r
211         xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );\r
212 \r
213         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
214         in use.  The queue registry is provided as a means for kernel aware\r
215         debuggers to locate queues and has no purpose if a kernel aware debugger\r
216         is not being used.  The call to vQueueAddToRegistry() will be removed\r
217         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
218         defined to be less than 1. */\r
219         vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );\r
220         vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );\r
221 }\r
222 /*-----------------------------------------------------------*/\r
223 \r
224 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource )\r
225 {\r
226         if( uxValue < intqNUM_VALUES_TO_LOG )\r
227         {\r
228                 /* We don't expect to receive the same value twice, so if the value\r
229                 has already been marked as received an error has occurred. */\r
230                 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )\r
231                 {\r
232                         prvQueueAccessLogError( __LINE__ );\r
233                 }\r
234 \r
235                 /* Log that this value has been received. */\r
236                 ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;\r
237         }\r
238 }\r
239 /*-----------------------------------------------------------*/\r
240 \r
241 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource )\r
242 {\r
243         if( uxValue < intqNUM_VALUES_TO_LOG )\r
244         {\r
245                 /* We don't expect to receive the same value twice, so if the value\r
246                 has already been marked as received an error has occurred. */\r
247                 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )\r
248                 {\r
249                         prvQueueAccessLogError( __LINE__ );\r
250                 }\r
251 \r
252                 /* Log that this value has been received. */\r
253                 ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;\r
254         }\r
255 }\r
256 /*-----------------------------------------------------------*/\r
257 \r
258 static void prvQueueAccessLogError( UBaseType_t uxLine )\r
259 {\r
260         /* Latch the line number that caused the error. */\r
261         xErrorLine = uxLine;\r
262         xErrorStatus = pdFAIL;\r
263 }\r
264 /*-----------------------------------------------------------*/\r
265 \r
266 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )\r
267 {\r
268 UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;\r
269 \r
270         /* The timer should not be started until after the scheduler has started.\r
271         More than one task is running this code so we check the parameter value\r
272         to determine which task should start the timer. */\r
273         if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
274         {\r
275                 vInitialiseTimerForIntQueueTest();\r
276         }\r
277 \r
278         for( ;; )\r
279         {\r
280                 /* Block waiting to receive a value from the normally empty queue.\r
281                 Interrupts will write to the queue so we should receive a value. */\r
282                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )\r
283                 {\r
284                         prvQueueAccessLogError( __LINE__ );\r
285                 }\r
286                 else\r
287                 {\r
288                         /* Note which value was received so we can check all expected\r
289                         values are received and no values are duplicated. */\r
290                         prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );\r
291                 }\r
292 \r
293                 /* Ensure the other task running this code gets a chance to execute. */\r
294                 taskYIELD();\r
295 \r
296                 if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
297                 {\r
298                         /* Have we received all the expected values? */\r
299                         if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
300                         {\r
301                                 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );\r
302 \r
303                                 uxTask1 = 0;\r
304                                 uxTask2 = 0;\r
305                                 uxInterrupts = 0;\r
306 \r
307                                 /* Loop through the array, checking that both tasks have\r
308                                 placed values into the array, and that no values are missing.\r
309                                 Start at 1 as we expect position 0 to be unused. */\r
310                                 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
311                                 {\r
312                                         if( ucNormallyEmptyReceivedValues[ ux ] == 0 )\r
313                                         {\r
314                                                 /* A value is missing. */\r
315                                                 prvQueueAccessLogError( __LINE__ );\r
316                                         }\r
317                                         else\r
318                                         {\r
319                                                 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )\r
320                                                 {\r
321                                                         /* Value was placed into the array by task 1. */\r
322                                                         uxTask1++;\r
323                                                 }\r
324                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )\r
325                                                 {\r
326                                                         /* Value was placed into the array by task 2. */\r
327                                                         uxTask2++;\r
328                                                 }\r
329                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
330                                                 {\r
331                                                         uxInterrupts++;\r
332                                                 }\r
333                                         }\r
334                                 }\r
335 \r
336                                 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )\r
337                                 {\r
338                                         /* Only task 2 seemed to log any values. */\r
339                                         uxErrorCount1++;\r
340                                         if( uxErrorCount1 > 2 )\r
341                                         {\r
342                                                 prvQueueAccessLogError( __LINE__ );\r
343                                         }\r
344                                 }\r
345                                 else\r
346                                 {\r
347                                         uxErrorCount1 = 0;\r
348                                 }\r
349 \r
350                                 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT  )\r
351                                 {\r
352                                         /* Only task 1 seemed to log any values. */\r
353                                         uxErrorCount2++;\r
354                                         if( uxErrorCount2 > 2 )\r
355                                         {\r
356                                                 prvQueueAccessLogError( __LINE__ );\r
357                                         }\r
358                                 }\r
359                                 else\r
360                                 {\r
361                                         uxErrorCount2 = 0;\r
362                                 }\r
363 \r
364                                 if( uxInterrupts == 0 )\r
365                                 {\r
366                                         prvQueueAccessLogError( __LINE__ );\r
367                                 }\r
368 \r
369                                 /* Clear the array again, ready to start a new cycle. */\r
370                                 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );\r
371 \r
372                                 uxHighPriorityLoops1++;\r
373                                 uxValueForNormallyEmptyQueue = 0;\r
374 \r
375                                 /* Suspend ourselves, allowing the lower priority task to\r
376                                 actually receive something from the queue.  Until now it\r
377                                 will have been prevented from doing so by the higher\r
378                                 priority tasks.  The lower priority task will resume us\r
379                                 if it receives something.  We will then resume the other\r
380                                 higher priority task. */\r
381                                 vTaskSuspend( NULL );\r
382                                 vTaskResume( xHighPriorityNormallyEmptyTask2 );\r
383                         }\r
384                 }\r
385         }\r
386 }\r
387 /*-----------------------------------------------------------*/\r
388 \r
389 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )\r
390 {\r
391 UBaseType_t uxValue, uxRxed;\r
392 \r
393         /* The parameters are not being used so avoid compiler warnings. */\r
394         ( void ) pvParameters;\r
395 \r
396         for( ;; )\r
397         {\r
398                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )\r
399                 {\r
400                         /* A value should only be obtained when the high priority task is\r
401                         suspended. */\r
402                         if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )\r
403                         {\r
404                                 prvQueueAccessLogError( __LINE__ );\r
405                         }\r
406 \r
407                         prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );\r
408 \r
409                         /* Wake the higher priority task again. */\r
410                         vTaskResume( xHighPriorityNormallyEmptyTask1 );\r
411                         uxLowPriorityLoops1++;\r
412                 }\r
413                 else\r
414                 {\r
415                         /* Raise our priority while we send so we can preempt the higher\r
416                         priority task, and ensure we get the Tx value into the queue. */\r
417                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
418 \r
419                         portENTER_CRITICAL();\r
420                         {\r
421                                 uxValueForNormallyEmptyQueue++;\r
422                                 uxValue = uxValueForNormallyEmptyQueue;\r
423                         }\r
424                         portEXIT_CRITICAL();\r
425 \r
426                         if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
427                         {\r
428                                 prvQueueAccessLogError( __LINE__ );\r
429                         }\r
430 \r
431                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
432                 }\r
433         }\r
434 }\r
435 /*-----------------------------------------------------------*/\r
436 \r
437 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )\r
438 {\r
439 UBaseType_t uxValueToTx, ux, uxInterrupts;\r
440 \r
441         /* The parameters are not being used so avoid compiler warnings. */\r
442         ( void ) pvParameters;\r
443 \r
444         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
445         high priority tasks. */\r
446         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
447         {\r
448                 portENTER_CRITICAL();\r
449                 {\r
450                         uxValueForNormallyFullQueue++;\r
451                         uxValueToTx = uxValueForNormallyFullQueue;\r
452                 }\r
453                 portEXIT_CRITICAL();\r
454 \r
455                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
456         }\r
457 \r
458         for( ;; )\r
459         {\r
460                 portENTER_CRITICAL();\r
461                 {\r
462                         uxValueForNormallyFullQueue++;\r
463                         uxValueToTx = uxValueForNormallyFullQueue;\r
464                 }\r
465                 portEXIT_CRITICAL();\r
466 \r
467                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
468                 {\r
469                         /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not\r
470                         expect it to ever time out. */\r
471                         prvQueueAccessLogError( __LINE__ );\r
472                 }\r
473 \r
474                 /* Allow the other task running this code to run. */\r
475                 taskYIELD();\r
476 \r
477                 /* Have all the expected values been sent to the queue? */\r
478                 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
479                 {\r
480                         /* Make sure the other high priority task completes its send of\r
481                         any values below intqNUM_VALUE_TO_LOG. */\r
482                         vTaskDelay( intqSHORT_DELAY );\r
483 \r
484                         vTaskSuspend( xHighPriorityNormallyFullTask2 );\r
485 \r
486                         if( xWasSuspended == pdTRUE )\r
487                         {\r
488                                 /* We would have expected the other high priority task to have\r
489                                 set this back to false by now. */\r
490                                 prvQueueAccessLogError( __LINE__ );\r
491                         }\r
492 \r
493                         /* Set the suspended flag so an error is not logged if the other\r
494                         task recognises a time out when it is unsuspended. */\r
495                         xWasSuspended = pdTRUE;\r
496 \r
497                         /* Check interrupts are also sending. */\r
498                         uxInterrupts = 0U;\r
499 \r
500                         /* Start at 1 as we expect position 0 to be unused. */\r
501                         for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
502                         {\r
503                                 if( ucNormallyFullReceivedValues[ ux ] == 0 )\r
504                                 {\r
505                                         /* A value was missing. */\r
506                                         prvQueueAccessLogError( __LINE__ );\r
507                                 }\r
508                                 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
509                                 {\r
510                                         uxInterrupts++;\r
511                                 }\r
512                         }\r
513 \r
514                         if( uxInterrupts == 0 )\r
515                         {\r
516                                 /* No writes from interrupts were found.  Are interrupts\r
517                                 actually running? */\r
518                                 prvQueueAccessLogError( __LINE__ );\r
519                         }\r
520 \r
521                         /* Reset the array ready for the next cycle. */\r
522                         memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );\r
523 \r
524                         uxHighPriorityLoops2++;\r
525                         uxValueForNormallyFullQueue = 0;\r
526 \r
527                         /* Suspend ourselves, allowing the lower priority task to\r
528                         actually receive something from the queue.  Until now it\r
529                         will have been prevented from doing so by the higher\r
530                         priority tasks.  The lower priority task will resume us\r
531                         if it receives something.  We will then resume the other\r
532                         higher priority task. */\r
533                         vTaskSuspend( NULL );\r
534                         vTaskResume( xHighPriorityNormallyFullTask2 );\r
535                 }\r
536         }\r
537 }\r
538 /*-----------------------------------------------------------*/\r
539 \r
540 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )\r
541 {\r
542 UBaseType_t uxValueToTx, ux;\r
543 \r
544         /* The parameters are not being used so avoid compiler warnings. */\r
545         ( void ) pvParameters;\r
546 \r
547         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
548         high priority tasks. */\r
549         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
550         {\r
551                 portENTER_CRITICAL();\r
552                 {\r
553                         uxValueForNormallyFullQueue++;\r
554                         uxValueToTx = uxValueForNormallyFullQueue;\r
555                 }\r
556                 portEXIT_CRITICAL();\r
557 \r
558                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
559         }\r
560 \r
561         for( ;; )\r
562         {\r
563                 portENTER_CRITICAL();\r
564                 {\r
565                         uxValueForNormallyFullQueue++;\r
566                         uxValueToTx = uxValueForNormallyFullQueue;\r
567                 }\r
568                 portEXIT_CRITICAL();\r
569 \r
570                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
571                 {\r
572                         if( xWasSuspended != pdTRUE )\r
573                         {\r
574                                 /* It is ok to time out if the task has been suspended. */\r
575                                 prvQueueAccessLogError( __LINE__ );\r
576                         }\r
577                 }\r
578 \r
579                 xWasSuspended = pdFALSE;\r
580 \r
581                 taskYIELD();\r
582         }\r
583 }\r
584 /*-----------------------------------------------------------*/\r
585 \r
586 static void prvLowerPriorityNormallyFullTask( void *pvParameters )\r
587 {\r
588 UBaseType_t uxValue, uxTxed = 9999;\r
589 \r
590         /* The parameters are not being used so avoid compiler warnings. */\r
591         ( void ) pvParameters;\r
592 \r
593         for( ;; )\r
594         {\r
595                 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )\r
596                 {\r
597                         /* Should only succeed when the higher priority task is suspended */\r
598                         if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )\r
599                         {\r
600                                 prvQueueAccessLogError( __LINE__ );\r
601                         }\r
602 \r
603                         vTaskResume( xHighPriorityNormallyFullTask1 );\r
604                         uxLowPriorityLoops2++;\r
605                 }\r
606                 else\r
607                 {\r
608                         /* Raise our priority while we receive so we can preempt the higher\r
609                         priority task, and ensure we get the value from the queue. */\r
610                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
611 \r
612                         if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
613                         {\r
614                                 prvQueueAccessLogError( __LINE__ );\r
615                         }\r
616                         else\r
617                         {\r
618                                 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );\r
619                         }\r
620 \r
621                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
622                 }\r
623         }\r
624 }\r
625 /*-----------------------------------------------------------*/\r
626 \r
627 BaseType_t xFirstTimerHandler( void )\r
628 {\r
629 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
630 UBaseType_t uxRxedValue;\r
631 static UBaseType_t uxNextOperation = 0;\r
632 \r
633         /* Called from a timer interrupt.  Perform various read and write\r
634         accesses on the queues. */\r
635 \r
636         uxNextOperation++;\r
637 \r
638         if( uxNextOperation & ( UBaseType_t ) 0x01 )\r
639         {\r
640                 timerNORMALLY_EMPTY_TX();\r
641                 timerNORMALLY_EMPTY_TX();\r
642                 timerNORMALLY_EMPTY_TX();\r
643         }\r
644         else\r
645         {\r
646                 timerNORMALLY_FULL_RX();\r
647                 timerNORMALLY_FULL_RX();\r
648                 timerNORMALLY_FULL_RX();\r
649         }\r
650 \r
651         return xHigherPriorityTaskWoken;\r
652 }\r
653 /*-----------------------------------------------------------*/\r
654 \r
655 BaseType_t xSecondTimerHandler( void )\r
656 {\r
657 UBaseType_t uxRxedValue;\r
658 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
659 static UBaseType_t uxNextOperation = 0;\r
660 \r
661         /* Called from a timer interrupt.  Perform various read and write\r
662         accesses on the queues. */\r
663 \r
664         uxNextOperation++;\r
665 \r
666         if( uxNextOperation & ( UBaseType_t ) 0x01 )\r
667         {\r
668                 timerNORMALLY_EMPTY_TX();\r
669                 timerNORMALLY_EMPTY_TX();\r
670 \r
671                 timerNORMALLY_EMPTY_RX();\r
672                 timerNORMALLY_EMPTY_RX();\r
673         }\r
674         else\r
675         {\r
676                 timerNORMALLY_FULL_RX();\r
677                 timerNORMALLY_FULL_TX();\r
678                 timerNORMALLY_FULL_TX();\r
679                 timerNORMALLY_FULL_TX();\r
680         }\r
681 \r
682         return xHigherPriorityTaskWoken;\r
683 }\r
684 /*-----------------------------------------------------------*/\r
685 \r
686 \r
687 BaseType_t xAreIntQueueTasksStillRunning( void )\r
688 {\r
689 static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;\r
690 \r
691         /* xErrorStatus can be set outside of this function.  This function just\r
692         checks that all the tasks are still cycling. */\r
693 \r
694         if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )\r
695         {\r
696                 /* The high priority 1 task has stalled. */\r
697                 prvQueueAccessLogError( __LINE__ );\r
698         }\r
699 \r
700         uxLastHighPriorityLoops1 = uxHighPriorityLoops1;\r
701 \r
702         if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )\r
703         {\r
704                 /* The high priority 2 task has stalled. */\r
705                 prvQueueAccessLogError( __LINE__ );\r
706         }\r
707 \r
708         uxLastHighPriorityLoops2 = uxHighPriorityLoops2;\r
709 \r
710         if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )\r
711         {\r
712                 /* The low priority 1 task has stalled. */\r
713                 prvQueueAccessLogError( __LINE__ );\r
714         }\r
715 \r
716         uxLastLowPriorityLoops1 = uxLowPriorityLoops1;\r
717 \r
718         if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )\r
719         {\r
720                 /* The low priority 2 task has stalled. */\r
721                 prvQueueAccessLogError( __LINE__ );\r
722         }\r
723 \r
724         uxLastLowPriorityLoops2 = uxLowPriorityLoops2;\r
725 \r
726         return xErrorStatus;\r
727 }\r
728 \r