root/webserver/example/freeRTOSexample/EnergyMeters/Common/Minimal/AltBlock.c

Revision 14, 16.8 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

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