]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/blocktim.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / Common / Minimal / blocktim.c
1 /*\r
2     FreeRTOS V7.1.1 - Copyright (C) 2012 Real Time Engineers Ltd.\r
3         \r
4 \r
5     ***************************************************************************\r
6      *                                                                       *\r
7      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
8      *    Complete, revised, and edited pdf reference manuals are also       *\r
9      *    available.                                                         *\r
10      *                                                                       *\r
11      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
12      *    ensuring you get running as quickly as possible and with an        *\r
13      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
14      *    the FreeRTOS project to continue with its mission of providing     *\r
15      *    professional grade, cross platform, de facto standard solutions    *\r
16      *    for microcontrollers - completely free of charge!                  *\r
17      *                                                                       *\r
18      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
19      *                                                                       *\r
20      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
21      *                                                                       *\r
22     ***************************************************************************\r
23 \r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     >>>NOTE<<< The modification to the GPL is included to allow you to\r
31     distribute a combined work that includes FreeRTOS without being obliged to\r
32     provide the source code for proprietary components outside of the FreeRTOS\r
33     kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
34     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
35     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public\r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43     \r
44     ***************************************************************************\r
45      *                                                                       *\r
46      *    Having a problem?  Start by reading the FAQ "My application does   *\r
47      *    not run, what could be wrong?                                      *\r
48      *                                                                       *\r
49      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
50      *                                                                       *\r
51     ***************************************************************************\r
52 \r
53     \r
54     http://www.FreeRTOS.org - Documentation, training, latest information, \r
55     license and contact details.\r
56     \r
57     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
58     including FreeRTOS+Trace - an indispensable productivity tool.\r
59 \r
60     Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell \r
61     the code with commercial support, indemnification, and middleware, under \r
62     the OpenRTOS brand: http://www.OpenRTOS.com.  High Integrity Systems also\r
63     provide a safety engineered and independently SIL3 certified version under \r
64     the SafeRTOS brand: http://www.SafeRTOS.com.\r
65 */\r
66 \r
67 /*\r
68  * This file contains some test scenarios that ensure tasks do not exit queue\r
69  * send or receive functions prematurely.  A description of the tests is\r
70  * included within the code.\r
71  */\r
72 \r
73 /* Kernel includes. */\r
74 #include "FreeRTOS.h"\r
75 #include "task.h"\r
76 #include "queue.h"\r
77 \r
78 /* Demo includes. */\r
79 #include "blocktim.h"\r
80 \r
81 /* Task priorities.  Allow these to be overridden. */\r
82 #ifndef bktPRIMARY_PRIORITY\r
83         #define bktPRIMARY_PRIORITY             ( configMAX_PRIORITIES - 3 )\r
84 #endif\r
85 \r
86 #ifndef bktSECONDARY_PRIORITY\r
87         #define bktSECONDARY_PRIORITY   ( configMAX_PRIORITIES - 4 )\r
88 #endif\r
89 \r
90 /* Task behaviour. */\r
91 #define bktQUEUE_LENGTH                         ( 5 )\r
92 #define bktSHORT_WAIT                           ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )\r
93 #define bktPRIMARY_BLOCK_TIME           ( 10 )\r
94 #define bktALLOWABLE_MARGIN                     ( 15 )\r
95 #define bktTIME_TO_BLOCK                        ( 175 )\r
96 #define bktDONT_BLOCK                           ( ( portTickType ) 0 )\r
97 #define bktRUN_INDICATOR                        ( ( unsigned portBASE_TYPE ) 0x55 )\r
98 \r
99 /* The queue on which the tasks block. */\r
100 static xQueueHandle xTestQueue;\r
101 \r
102 /* Handle to the secondary task is required by the primary task for calls\r
103 to vTaskSuspend/Resume(). */\r
104 static xTaskHandle xSecondary;\r
105 \r
106 /* Used to ensure that tasks are still executing without error. */\r
107 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;\r
108 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;\r
109 \r
110 /* Provides a simple mechanism for the primary task to know when the\r
111 secondary task has executed. */\r
112 static volatile unsigned portBASE_TYPE xRunIndicator;\r
113 \r
114 /* The two test tasks.  Their behaviour is commented within the files. */\r
115 static void vPrimaryBlockTimeTestTask( void *pvParameters );\r
116 static void vSecondaryBlockTimeTestTask( void *pvParameters );\r
117 \r
118 /*-----------------------------------------------------------*/\r
119 \r
120 void vCreateBlockTimeTasks( void )\r
121 {\r
122         /* Create the queue on which the two tasks block. */\r
123     xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );\r
124 \r
125         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
126         in use.  The queue registry is provided as a means for kernel aware\r
127         debuggers to locate queues and has no purpose if a kernel aware debugger\r
128         is not being used.  The call to vQueueAddToRegistry() will be removed\r
129         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
130         defined to be less than 1. */\r
131         vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );\r
132 \r
133         /* Create the two test tasks. */\r
134         xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );\r
135         xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );\r
136 }\r
137 /*-----------------------------------------------------------*/\r
138 \r
139 static void vPrimaryBlockTimeTestTask( void *pvParameters )\r
140 {\r
141 portBASE_TYPE xItem, xData;\r
142 portTickType xTimeWhenBlocking;\r
143 portTickType xTimeToBlock, xBlockedTime;\r
144 \r
145         ( void ) pvParameters;\r
146 \r
147         for( ;; )\r
148         {\r
149                 /*********************************************************************\r
150         Test 1\r
151 \r
152         Simple block time wakeup test on queue receives. */\r
153                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
154                 {\r
155                         /* The queue is empty. Attempt to read from the queue using a block\r
156                         time.  When we wake, ensure the delta in time is as expected. */\r
157                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
158 \r
159                         xTimeWhenBlocking = xTaskGetTickCount();\r
160 \r
161                         /* We should unblock after xTimeToBlock having not received\r
162                         anything on the queue. */\r
163                         if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )\r
164                         {\r
165                                 xErrorOccurred = pdTRUE;\r
166                         }\r
167 \r
168                         /* How long were we blocked for? */\r
169                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
170 \r
171                         if( xBlockedTime < xTimeToBlock )\r
172                         {\r
173                                 /* Should not have blocked for less than we requested. */\r
174                                 xErrorOccurred = pdTRUE;\r
175                         }\r
176 \r
177                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
178                         {\r
179                                 /* Should not have blocked for longer than we requested,\r
180                                 although we would not necessarily run as soon as we were\r
181                                 unblocked so a margin is allowed. */\r
182                                 xErrorOccurred = pdTRUE;\r
183                         }\r
184                 }\r
185 \r
186                 /*********************************************************************\r
187         Test 2\r
188 \r
189         Simple block time wakeup test on queue sends.\r
190 \r
191                 First fill the queue.  It should be empty so all sends should pass. */\r
192                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
193                 {\r
194                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
195                         {\r
196                                 xErrorOccurred = pdTRUE;\r
197                         }\r
198 \r
199                         #if configUSE_PREEMPTION == 0\r
200                                 taskYIELD();\r
201                         #endif\r
202                 }\r
203 \r
204                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
205                 {\r
206                         /* The queue is full. Attempt to write to the queue using a block\r
207                         time.  When we wake, ensure the delta in time is as expected. */\r
208                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
209 \r
210                         xTimeWhenBlocking = xTaskGetTickCount();\r
211 \r
212                         /* We should unblock after xTimeToBlock having not received\r
213                         anything on the queue. */\r
214                         if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )\r
215                         {\r
216                                 xErrorOccurred = pdTRUE;\r
217                         }\r
218 \r
219                         /* How long were we blocked for? */\r
220                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
221 \r
222                         if( xBlockedTime < xTimeToBlock )\r
223                         {\r
224                                 /* Should not have blocked for less than we requested. */\r
225                                 xErrorOccurred = pdTRUE;\r
226                         }\r
227 \r
228                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
229                         {\r
230                                 /* Should not have blocked for longer than we requested,\r
231                                 although we would not necessarily run as soon as we were\r
232                                 unblocked so a margin is allowed. */\r
233                                 xErrorOccurred = pdTRUE;\r
234                         }\r
235                 }\r
236 \r
237                 /*********************************************************************\r
238         Test 3\r
239 \r
240                 Wake the other task, it will block attempting to post to the queue.\r
241                 When we read from the queue the other task will wake, but before it\r
242                 can run we will post to the queue again.  When the other task runs it\r
243                 will find the queue still full, even though it was woken.  It should\r
244                 recognise that its block time has not expired and return to block for\r
245                 the remains of its block time.\r
246 \r
247                 Wake the other task so it blocks attempting to post to the already\r
248                 full queue. */\r
249                 xRunIndicator = 0;\r
250                 vTaskResume( xSecondary );\r
251 \r
252                 /* We need to wait a little to ensure the other task executes. */\r
253                 while( xRunIndicator != bktRUN_INDICATOR )\r
254                 {\r
255                         /* The other task has not yet executed. */\r
256                         vTaskDelay( bktSHORT_WAIT );\r
257                 }\r
258                 /* Make sure the other task is blocked on the queue. */\r
259                 vTaskDelay( bktSHORT_WAIT );\r
260                 xRunIndicator = 0;\r
261 \r
262                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
263                 {\r
264                         /* Now when we make space on the queue the other task should wake\r
265                         but not execute as this task has higher priority. */\r
266                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
267                         {\r
268                                 xErrorOccurred = pdTRUE;\r
269                         }\r
270 \r
271                         /* Now fill the queue again before the other task gets a chance to\r
272                         execute.  If the other task had executed we would find the queue\r
273                         full ourselves, and the other task have set xRunIndicator. */\r
274                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
275                         {\r
276                                 xErrorOccurred = pdTRUE;\r
277                         }\r
278 \r
279                         if( xRunIndicator == bktRUN_INDICATOR )\r
280                         {\r
281                                 /* The other task should not have executed. */\r
282                                 xErrorOccurred = pdTRUE;\r
283                         }\r
284 \r
285                         /* Raise the priority of the other task so it executes and blocks\r
286                         on the queue again. */\r
287                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
288 \r
289                         /* The other task should now have re-blocked without exiting the\r
290                         queue function. */\r
291                         if( xRunIndicator == bktRUN_INDICATOR )\r
292                         {\r
293                                 /* The other task should not have executed outside of the\r
294                                 queue function. */\r
295                                 xErrorOccurred = pdTRUE;\r
296                         }\r
297 \r
298                         /* Set the priority back down. */\r
299                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
300                 }\r
301 \r
302                 /* Let the other task timeout.  When it unblockes it will check that it\r
303                 unblocked at the correct time, then suspend itself. */\r
304                 while( xRunIndicator != bktRUN_INDICATOR )\r
305                 {\r
306                         vTaskDelay( bktSHORT_WAIT );\r
307                 }\r
308                 vTaskDelay( bktSHORT_WAIT );\r
309                 xRunIndicator = 0;\r
310 \r
311 \r
312                 /*********************************************************************\r
313         Test 4\r
314 \r
315                 As per test 3 - but with the send and receive the other way around.\r
316                 The other task blocks attempting to read from the queue.\r
317 \r
318                 Empty the queue.  We should find that it is full. */\r
319                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
320                 {\r
321                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
322                         {\r
323                                 xErrorOccurred = pdTRUE;\r
324                         }\r
325                 }\r
326 \r
327                 /* Wake the other task so it blocks attempting to read from  the\r
328                 already empty queue. */\r
329                 vTaskResume( xSecondary );\r
330 \r
331                 /* We need to wait a little to ensure the other task executes. */\r
332                 while( xRunIndicator != bktRUN_INDICATOR )\r
333                 {\r
334                         vTaskDelay( bktSHORT_WAIT );\r
335                 }\r
336                 vTaskDelay( bktSHORT_WAIT );\r
337                 xRunIndicator = 0;\r
338 \r
339                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
340                 {\r
341                         /* Now when we place an item on the queue the other task should\r
342                         wake but not execute as this task has higher priority. */\r
343                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
344                         {\r
345                                 xErrorOccurred = pdTRUE;\r
346                         }\r
347 \r
348                         /* Now empty the queue again before the other task gets a chance to\r
349                         execute.  If the other task had executed we would find the queue\r
350                         empty ourselves, and the other task would be suspended. */\r
351                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
352                         {\r
353                                 xErrorOccurred = pdTRUE;\r
354                         }\r
355 \r
356                         if( xRunIndicator == bktRUN_INDICATOR )\r
357                         {\r
358                                 /* The other task should not have executed. */\r
359                                 xErrorOccurred = pdTRUE;\r
360                         }\r
361 \r
362                         /* Raise the priority of the other task so it executes and blocks\r
363                         on the queue again. */\r
364                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
365 \r
366                         /* The other task should now have re-blocked without exiting the\r
367                         queue function. */\r
368                         if( xRunIndicator == bktRUN_INDICATOR )\r
369                         {\r
370                                 /* The other task should not have executed outside of the\r
371                                 queue function. */\r
372                                 xErrorOccurred = pdTRUE;\r
373                         }\r
374                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
375                 }\r
376 \r
377                 /* Let the other task timeout.  When it unblockes it will check that it\r
378                 unblocked at the correct time, then suspend itself. */\r
379                 while( xRunIndicator != bktRUN_INDICATOR )\r
380                 {\r
381                         vTaskDelay( bktSHORT_WAIT );\r
382                 }\r
383                 vTaskDelay( bktSHORT_WAIT );\r
384 \r
385                 xPrimaryCycles++;\r
386         }\r
387 }\r
388 /*-----------------------------------------------------------*/\r
389 \r
390 static void vSecondaryBlockTimeTestTask( void *pvParameters )\r
391 {\r
392 portTickType xTimeWhenBlocking, xBlockedTime;\r
393 portBASE_TYPE xData;\r
394 \r
395         ( void ) pvParameters;\r
396 \r
397         for( ;; )\r
398         {\r
399                 /*********************************************************************\r
400         Test 1 and 2\r
401 \r
402                 This task does does not participate in these tests. */\r
403                 vTaskSuspend( NULL );\r
404 \r
405                 /*********************************************************************\r
406         Test 3\r
407 \r
408                 The first thing we do is attempt to read from the queue.  It should be\r
409                 full so we block.  Note the time before we block so we can check the\r
410                 wake time is as per that expected. */\r
411                 xTimeWhenBlocking = xTaskGetTickCount();\r
412 \r
413                 /* We should unblock after bktTIME_TO_BLOCK having not sent\r
414                 anything to the queue. */\r
415                 xData = 0;\r
416                 xRunIndicator = bktRUN_INDICATOR;\r
417                 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )\r
418                 {\r
419                         xErrorOccurred = pdTRUE;\r
420                 }\r
421 \r
422                 /* How long were we inside the send function? */\r
423                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
424 \r
425                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
426                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
427                 {\r
428                         xErrorOccurred = pdTRUE;\r
429                 }\r
430 \r
431                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
432                 either.  A margin is permitted as we would not necessarily run as\r
433                 soon as we unblocked. */\r
434                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
435                 {\r
436                         xErrorOccurred = pdTRUE;\r
437                 }\r
438 \r
439                 /* Suspend ready for test 3. */\r
440                 xRunIndicator = bktRUN_INDICATOR;\r
441                 vTaskSuspend( NULL );\r
442 \r
443                 /*********************************************************************\r
444         Test 4\r
445 \r
446                 As per test three, but with the send and receive reversed. */\r
447                 xTimeWhenBlocking = xTaskGetTickCount();\r
448 \r
449                 /* We should unblock after bktTIME_TO_BLOCK having not received\r
450                 anything on the queue. */\r
451                 xRunIndicator = bktRUN_INDICATOR;\r
452                 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )\r
453                 {\r
454                         xErrorOccurred = pdTRUE;\r
455                 }\r
456 \r
457                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
458 \r
459                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
460                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
461                 {\r
462                         xErrorOccurred = pdTRUE;\r
463                 }\r
464 \r
465                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
466                 either.  A margin is permitted as we would not necessarily run as soon\r
467                 as we unblocked. */\r
468                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
469                 {\r
470                         xErrorOccurred = pdTRUE;\r
471                 }\r
472 \r
473                 xRunIndicator = bktRUN_INDICATOR;\r
474 \r
475                 xSecondaryCycles++;\r
476         }\r
477 }\r
478 /*-----------------------------------------------------------*/\r
479 \r
480 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )\r
481 {\r
482 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;\r
483 portBASE_TYPE xReturn = pdPASS;\r
484 \r
485         /* Have both tasks performed at least one cycle since this function was\r
486         last called? */\r
487         if( xPrimaryCycles == xLastPrimaryCycleCount )\r
488         {\r
489                 xReturn = pdFAIL;\r
490         }\r
491 \r
492         if( xSecondaryCycles == xLastSecondaryCycleCount )\r
493         {\r
494                 xReturn = pdFAIL;\r
495         }\r
496 \r
497         if( xErrorOccurred == pdTRUE )\r
498         {\r
499                 xReturn = pdFAIL;\r
500         }\r
501 \r
502         xLastSecondaryCycleCount = xSecondaryCycles;\r
503         xLastPrimaryCycleCount = xPrimaryCycles;\r
504 \r
505         return xReturn;\r
506 }\r