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