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