]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/AltBlock.c
Prepare for V7.2.0 release.
[freertos] / FreeRTOS / Demo / Common / Minimal / AltBlock.c
1 /*\r
2     FreeRTOS V7.2.0 - 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 is a version of BlockTim.c that uses the light weight API.\r
69  *\r
70  * This file contains some test scenarios that ensure tasks do not exit queue\r
71  * send or receive functions prematurely.  A description of the tests is\r
72  * included within the code.\r
73  */\r
74 \r
75 /* Kernel includes. */\r
76 #include "FreeRTOS.h"\r
77 #include "task.h"\r
78 #include "queue.h"\r
79 \r
80 /* Demo includes. */\r
81 #include "AltBlock.h"\r
82 \r
83 /* Task priorities. */\r
84 #define bktPRIMARY_PRIORITY                     ( 3 )\r
85 #define bktSECONDARY_PRIORITY           ( 2 )\r
86 \r
87 /* Task behaviour. */\r
88 #define bktQUEUE_LENGTH                         ( 5 )\r
89 #define bktSHORT_WAIT                           ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )\r
90 #define bktPRIMARY_BLOCK_TIME           ( 10 )\r
91 #define bktALLOWABLE_MARGIN                     ( 12 )\r
92 #define bktTIME_TO_BLOCK                        ( 175 )\r
93 #define bktDONT_BLOCK                           ( ( portTickType ) 0 )\r
94 #define bktRUN_INDICATOR                        ( ( unsigned portBASE_TYPE ) 0x55 )\r
95 \r
96 /* The queue on which the tasks block. */\r
97 static xQueueHandle xTestQueue;\r
98 \r
99 /* Handle to the secondary task is required by the primary task for calls\r
100 to vTaskSuspend/Resume(). */\r
101 static xTaskHandle xSecondary;\r
102 \r
103 /* Used to ensure that tasks are still executing without error. */\r
104 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;\r
105 static portBASE_TYPE xErrorOccurred = pdFALSE;\r
106 \r
107 /* Provides a simple mechanism for the primary task to know when the\r
108 secondary task has executed. */\r
109 static volatile unsigned portBASE_TYPE xRunIndicator;\r
110 \r
111 /* The two test tasks.  Their behaviour is commented within the files. */\r
112 static void vPrimaryBlockTimeTestTask( void *pvParameters );\r
113 static void vSecondaryBlockTimeTestTask( void *pvParameters );\r
114 \r
115 /*-----------------------------------------------------------*/\r
116 \r
117 void vCreateAltBlockTimeTasks( void )\r
118 {\r
119         /* Create the queue on which the two tasks block. */\r
120     xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );\r
121 \r
122         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
123         in use.  The queue registry is provided as a means for kernel aware \r
124         debuggers to locate queues and has no purpose if a kernel aware debugger\r
125         is not being used.  The call to vQueueAddToRegistry() will be removed\r
126         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
127         defined to be less than 1. */\r
128         vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );\r
129 \r
130 \r
131         /* Create the two test tasks. */\r
132         xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );\r
133         xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );\r
134 }\r
135 /*-----------------------------------------------------------*/\r
136 \r
137 static void vPrimaryBlockTimeTestTask( void *pvParameters )\r
138 {\r
139 portBASE_TYPE xItem, xData;\r
140 portTickType xTimeWhenBlocking;\r
141 portTickType xTimeToBlock, xBlockedTime;\r
142 \r
143         #ifdef USE_STDIO\r
144         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
145         \r
146                 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";\r
147 \r
148                 /* Queue a message for printing to say the task has started. */\r
149                 vPrintDisplayMessage( &pcTaskStartMsg );\r
150         #endif\r
151 \r
152         ( void ) pvParameters;\r
153 \r
154         for( ;; )\r
155         {\r
156                 /*********************************************************************\r
157         Test 1\r
158 \r
159         Simple block time wakeup test on queue receives. */\r
160                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
161                 {\r
162                         /* The queue is empty. Attempt to read from the queue using a block\r
163                         time.  When we wake, ensure the delta in time is as expected. */\r
164                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
165 \r
166                         /* A critical section is used to minimise the jitter in the time\r
167                         measurements. */\r
168                         portENTER_CRITICAL();\r
169                         {\r
170                                 xTimeWhenBlocking = xTaskGetTickCount();\r
171                                 \r
172                                 /* We should unblock after xTimeToBlock having not received\r
173                                 anything on the queue. */\r
174                                 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )\r
175                                 {\r
176                                         xErrorOccurred = pdTRUE;\r
177                                 }\r
178 \r
179                                 /* How long were we blocked for? */\r
180                                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
181                         }\r
182                         portEXIT_CRITICAL();\r
183 \r
184                         if( xBlockedTime < xTimeToBlock )\r
185                         {\r
186                                 /* Should not have blocked for less than we requested. */\r
187                                 xErrorOccurred = pdTRUE;\r
188                         }\r
189 \r
190                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
191                         {\r
192                                 /* Should not have blocked for longer than we requested,\r
193                                 although we would not necessarily run as soon as we were\r
194                                 unblocked so a margin is allowed. */\r
195                                 xErrorOccurred = pdTRUE;\r
196                         }\r
197                 }\r
198 \r
199 \r
200                 #if configUSE_PREEMPTION == 0\r
201                         taskYIELD();\r
202                 #endif\r
203 \r
204 \r
205                 /*********************************************************************\r
206         Test 2\r
207 \r
208         Simple block time wakeup test on queue sends.\r
209 \r
210                 First fill the queue.  It should be empty so all sends should pass. */\r
211                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
212                 {\r
213                         if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
214                         {\r
215                                 xErrorOccurred = pdTRUE;\r
216                         }\r
217                 }\r
218 \r
219                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
220                 {\r
221                         /* The queue is full. Attempt to write to the queue using a block\r
222                         time.  When we wake, ensure the delta in time is as expected. */\r
223                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
224 \r
225                         portENTER_CRITICAL();\r
226                         {\r
227                                 xTimeWhenBlocking = xTaskGetTickCount();\r
228                                 \r
229                                 /* We should unblock after xTimeToBlock having not received\r
230                                 anything on the queue. */\r
231                                 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )\r
232                                 {\r
233                                         xErrorOccurred = pdTRUE;\r
234                                 }\r
235 \r
236                                 /* How long were we blocked for? */\r
237                                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
238                         }\r
239                         portEXIT_CRITICAL();\r
240 \r
241                         if( xBlockedTime < xTimeToBlock )\r
242                         {\r
243                                 /* Should not have blocked for less than we requested. */\r
244                                 xErrorOccurred = pdTRUE;\r
245                         }\r
246 \r
247                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
248                         {\r
249                                 /* Should not have blocked for longer than we requested,\r
250                                 although we would not necessarily run as soon as we were\r
251                                 unblocked so a margin is allowed. */\r
252                                 xErrorOccurred = pdTRUE;\r
253                         }\r
254                 }\r
255 \r
256                 #if configUSE_PREEMPTION == 0\r
257                         taskYIELD();\r
258                 #endif\r
259 \r
260                 \r
261                 /*********************************************************************\r
262         Test 3\r
263 \r
264                 Wake the other task, it will block attempting to post to the queue.\r
265                 When we read from the queue the other task will wake, but before it\r
266                 can run we will post to the queue again.  When the other task runs it\r
267                 will find the queue still full, even though it was woken.  It should\r
268                 recognise that its block time has not expired and return to block for\r
269                 the remains of its block time.\r
270 \r
271                 Wake the other task so it blocks attempting to post to the already\r
272                 full queue. */\r
273                 xRunIndicator = 0;\r
274                 vTaskResume( xSecondary );\r
275 \r
276                 /* We need to wait a little to ensure the other task executes. */\r
277                 while( xRunIndicator != bktRUN_INDICATOR )\r
278                 {\r
279                         /* The other task has not yet executed. */\r
280                         vTaskDelay( bktSHORT_WAIT );\r
281                 }\r
282                 /* Make sure the other task is blocked on the queue. */\r
283                 vTaskDelay( bktSHORT_WAIT );\r
284                 xRunIndicator = 0;\r
285 \r
286                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
287                 {\r
288                         /* Now when we make space on the queue the other task should wake\r
289                         but not execute as this task has higher priority. */                            \r
290                         if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
291                         {\r
292                                 xErrorOccurred = pdTRUE;\r
293                         }\r
294 \r
295                         /* Now fill the queue again before the other task gets a chance to\r
296                         execute.  If the other task had executed we would find the queue\r
297                         full ourselves, and the other task have set xRunIndicator. */\r
298                         if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
299                         {\r
300                                 xErrorOccurred = pdTRUE;\r
301                         }\r
302 \r
303                         if( xRunIndicator == bktRUN_INDICATOR )\r
304                         {\r
305                                 /* The other task should not have executed. */\r
306                                 xErrorOccurred = pdTRUE;\r
307                         }\r
308 \r
309                         /* Raise the priority of the other task so it executes and blocks\r
310                         on the queue again. */\r
311                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
312 \r
313                         /* The other task should now have re-blocked without exiting the\r
314                         queue function. */\r
315                         if( xRunIndicator == bktRUN_INDICATOR )\r
316                         {\r
317                                 /* The other task should not have executed outside of the\r
318                                 queue function. */\r
319                                 xErrorOccurred = pdTRUE;\r
320                         }\r
321 \r
322                         /* Set the priority back down. */\r
323                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );                  \r
324                 }\r
325 \r
326                 /* Let the other task timeout.  When it unblockes it will check that it\r
327                 unblocked at the correct time, then suspend itself. */\r
328                 while( xRunIndicator != bktRUN_INDICATOR )\r
329                 {\r
330                         vTaskDelay( bktSHORT_WAIT );\r
331                 }\r
332                 vTaskDelay( bktSHORT_WAIT );\r
333                 xRunIndicator = 0;\r
334 \r
335                 #if configUSE_PREEMPTION == 0\r
336                         taskYIELD();\r
337                 #endif\r
338 \r
339                 /*********************************************************************\r
340         Test 4\r
341 \r
342                 As per test 3 - but with the send and receive the other way around.\r
343                 The other task blocks attempting to read from the queue.\r
344 \r
345                 Empty the queue.  We should find that it is full. */\r
346                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
347                 {\r
348                         if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
349                         {\r
350                                 xErrorOccurred = pdTRUE;\r
351                         }\r
352                 }\r
353                 \r
354                 /* Wake the other task so it blocks attempting to read from  the\r
355                 already empty queue. */\r
356                 vTaskResume( xSecondary );\r
357 \r
358                 /* We need to wait a little to ensure the other task executes. */\r
359                 while( xRunIndicator != bktRUN_INDICATOR )\r
360                 {\r
361                         vTaskDelay( bktSHORT_WAIT );\r
362                 }\r
363                 vTaskDelay( bktSHORT_WAIT );\r
364                 xRunIndicator = 0;\r
365 \r
366                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
367                 {\r
368                         /* Now when we place an item on the queue the other task should\r
369                         wake but not execute as this task has higher priority. */                               \r
370                         if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
371                         {\r
372                                 xErrorOccurred = pdTRUE;\r
373                         }\r
374 \r
375                         /* Now empty the queue again before the other task gets a chance to\r
376                         execute.  If the other task had executed we would find the queue\r
377                         empty ourselves, and the other task would be suspended. */\r
378                         if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
379                         {\r
380                                 xErrorOccurred = pdTRUE;\r
381                         }\r
382 \r
383                         if( xRunIndicator == bktRUN_INDICATOR )\r
384                         {\r
385                                 /* The other task should not have executed. */\r
386                                 xErrorOccurred = pdTRUE;\r
387                         }\r
388 \r
389                         /* Raise the priority of the other task so it executes and blocks\r
390                         on the queue again. */\r
391                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
392 \r
393                         /* The other task should now have re-blocked without exiting the\r
394                         queue function. */\r
395                         if( xRunIndicator == bktRUN_INDICATOR )\r
396                         {\r
397                                 /* The other task should not have executed outside of the\r
398                                 queue function. */\r
399                                 xErrorOccurred = pdTRUE;\r
400                         }\r
401                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );                  \r
402                 }\r
403 \r
404                 /* Let the other task timeout.  When it unblockes it will check that it\r
405                 unblocked at the correct time, then suspend itself. */\r
406                 while( xRunIndicator != bktRUN_INDICATOR )\r
407                 {\r
408                         vTaskDelay( bktSHORT_WAIT );\r
409                 }\r
410                 vTaskDelay( bktSHORT_WAIT );\r
411 \r
412                 xPrimaryCycles++;\r
413         }\r
414 }\r
415 /*-----------------------------------------------------------*/\r
416 \r
417 static void vSecondaryBlockTimeTestTask( void *pvParameters )\r
418 {\r
419 portTickType xTimeWhenBlocking, xBlockedTime;\r
420 portBASE_TYPE xData;\r
421 \r
422         #ifdef USE_STDIO\r
423         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
424         \r
425                 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";\r
426 \r
427                 /* Queue a message for printing to say the task has started. */\r
428                 vPrintDisplayMessage( &pcTaskStartMsg );\r
429         #endif\r
430 \r
431         ( void ) pvParameters;\r
432 \r
433         for( ;; )\r
434         {\r
435                 /*********************************************************************\r
436         Test 1 and 2\r
437 \r
438                 This task does does not participate in these tests. */\r
439                 vTaskSuspend( NULL );\r
440 \r
441                 /*********************************************************************\r
442         Test 3\r
443 \r
444                 The first thing we do is attempt to read from the queue.  It should be\r
445                 full so we block.  Note the time before we block so we can check the\r
446                 wake time is as per that expected. */\r
447                 portENTER_CRITICAL();\r
448                 {\r
449                         xTimeWhenBlocking = xTaskGetTickCount();\r
450                         \r
451                         /* We should unblock after bktTIME_TO_BLOCK having not received\r
452                         anything on the queue. */\r
453                         xData = 0;\r
454                         xRunIndicator = bktRUN_INDICATOR;\r
455                         if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )\r
456                         {\r
457                                 xErrorOccurred = pdTRUE;\r
458                         }\r
459 \r
460                         /* How long were we inside the send function? */\r
461                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
462                 }\r
463                 portEXIT_CRITICAL();\r
464 \r
465                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
466                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
467                 {\r
468                         xErrorOccurred = pdTRUE;\r
469                 }\r
470 \r
471                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
472                 either.  A margin is permitted as we would not necessarily run as\r
473                 soon as we unblocked. */\r
474                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
475                 {\r
476                         xErrorOccurred = pdTRUE;\r
477                 }\r
478 \r
479                 /* Suspend ready for test 3. */\r
480                 xRunIndicator = bktRUN_INDICATOR;\r
481                 vTaskSuspend( NULL );\r
482 \r
483                 /*********************************************************************\r
484         Test 4\r
485 \r
486                 As per test three, but with the send and receive reversed. */\r
487                 portENTER_CRITICAL();\r
488                 {\r
489                         xTimeWhenBlocking = xTaskGetTickCount();\r
490                         \r
491                         /* We should unblock after bktTIME_TO_BLOCK having not received\r
492                         anything on the queue. */\r
493                         xRunIndicator = bktRUN_INDICATOR;\r
494                         if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )\r
495                         {\r
496                                 xErrorOccurred = pdTRUE;\r
497                         }\r
498 \r
499                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
500                 }\r
501                 portEXIT_CRITICAL();\r
502 \r
503                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
504                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
505                 {\r
506                         xErrorOccurred = pdTRUE;\r
507                 }\r
508 \r
509                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
510                 either.  A margin is permitted as we would not necessarily run as soon\r
511                 as we unblocked. */\r
512                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
513                 {\r
514                         xErrorOccurred = pdTRUE;\r
515                 }\r
516 \r
517                 xRunIndicator = bktRUN_INDICATOR;\r
518 \r
519                 xSecondaryCycles++;\r
520         }\r
521 }\r
522 /*-----------------------------------------------------------*/\r
523 \r
524 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )\r
525 {\r
526 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;\r
527 portBASE_TYPE xReturn = pdPASS;\r
528 \r
529         /* Have both tasks performed at least one cycle since this function was\r
530         last called? */\r
531         if( xPrimaryCycles == xLastPrimaryCycleCount )\r
532         {\r
533                 xReturn = pdFAIL;\r
534         }\r
535 \r
536         if( xSecondaryCycles == xLastSecondaryCycleCount )\r
537         {\r
538                 xReturn = pdFAIL;\r
539         }\r
540 \r
541         if( xErrorOccurred == pdTRUE )\r
542         {\r
543                 xReturn = pdFAIL;\r
544         }\r
545 \r
546         xLastSecondaryCycleCount = xSecondaryCycles;\r
547         xLastPrimaryCycleCount = xPrimaryCycles;\r
548 \r
549         return xReturn;\r
550 }\r