]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/StaticAllocation.c
Notes:
[freertos] / FreeRTOS / Demo / Common / Minimal / StaticAllocation.c
1 /*\r
2     FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 \r
71 /*\r
72  * Demonstrates how to create FreeRTOS objects using pre-allocated memory,\r
73  * rather than the normal dynamically allocated memory, and tests objects being\r
74  * created and deleted with both statically allocated memory and dynamically\r
75  * allocated memory.\r
76  */\r
77 \r
78 /* Scheduler include files. */\r
79 #include "FreeRTOS.h"\r
80 #include "task.h"\r
81 #include "queue.h"\r
82 #include "semphr.h"\r
83 #include "event_groups.h"\r
84 #include "timers.h"\r
85 \r
86 /* Demo program include files. */\r
87 #include "StaticAllocation.h"\r
88 \r
89 /* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */\r
90 #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
91 \r
92 /* The priority at which the task that performs the tests is created. */\r
93 #define staticTASK_PRIORITY                                     ( tskIDLE_PRIORITY + 2 )\r
94 \r
95 /* The length of the queue, in items, not bytes, used in the queue static\r
96 allocation tests. */\r
97 #define staticQUEUE_LENGTH_IN_ITEMS                     ( 5 )\r
98 \r
99 /* A block time of 0 simply means "don't block". */\r
100 #define staticDONT_BLOCK                                        ( ( TickType_t ) 0 )\r
101 \r
102 /* Binary semaphores have a maximum count of 1. */\r
103 #define staticBINARY_SEMAPHORE_MAX_COUNT        ( 1 )\r
104 \r
105 /* The size of the stack used by the task that runs the tests. */\r
106 #define staticCREATOR_TASK_STACK_SIZE           ( configMINIMAL_STACK_SIZE * 2 )\r
107 \r
108 /* The number of times the software timer will execute before stopping itself. */\r
109 #define staticMAX_TIMER_CALLBACK_EXECUTIONS     ( 5 )\r
110 \r
111 \r
112 /*-----------------------------------------------------------*/\r
113 \r
114 /*\r
115  * The task that repeatedly creates and deletes statically allocated tasks, and\r
116  * other RTOS objects.\r
117  */\r
118 static void prvStaticallyAllocatedCreator( void *pvParameters );\r
119 \r
120 /*\r
121  * The callback function used by the software timer that is repeatedly created\r
122  * and deleted using both static and dynamically allocated memory.\r
123  */\r
124 static void prvTimerCallback( TimerHandle_t xExpiredTimer );\r
125 \r
126 /*\r
127  * A task that is created and deleted multiple times, using both statically and\r
128  * dynamically allocated stack and TCB.\r
129  */\r
130 static void prvStaticallyAllocatedTask( void *pvParameters );\r
131 \r
132 /*\r
133  * A function that demonstrates and tests the xTaskCreateStatic() API function\r
134  * by creating and then deleting tasks with both dynamically and statically\r
135  * allocated TCBs and stacks.\r
136  */\r
137 static void prvCreateAndDeleteStaticallyAllocatedTasks( void );\r
138 \r
139 /*\r
140  * A function that demonstrates and tests the xEventGroupCreateStatic() API\r
141  * function by creating and then deleting event groups using both dynamically\r
142  * and statically allocated event group structures.\r
143  */\r
144 static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void );\r
145 \r
146 /*\r
147  * A function that demonstrates and tests the xQueueCreateStatic() API function\r
148  * by creating and then deleting queues with both dynamically and statically\r
149  * allocated queue structures and queue storage areas.\r
150  */\r
151 static void prvCreateAndDeleteStaticallyAllocatedQueues( void );\r
152 \r
153 /*\r
154  * A function that demonstrates and tests the xSemaphoreCreateBinaryStatic() API\r
155  * macro by creating and then deleting binary semaphores with both dynamically\r
156  * and statically allocated semaphore structures.\r
157  */\r
158 static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void );\r
159 \r
160 /*\r
161  * A function that demonstrates and tests the xTimerCreateStatic() API macro by\r
162  * creating and then deleting software timers with both dynamically and\r
163  * statically allocated timer structures.\r
164  */\r
165 static void prvCreateAndDeleteStaticallyAllocatedTimers( void );\r
166 \r
167 /*\r
168  * A function that demonstrates and tests the xSemaphoreCreateMutexStatic() API\r
169  * macro by creating and then deleting mutexes with both dynamically and\r
170  * statically allocated semaphore structures.\r
171  */\r
172 static void prvCreateAndDeleteStaticallyAllocatedMutexes( void );\r
173 \r
174 /*\r
175  * A function that demonstrates and tests the xSemaphoreCreateCountingStatic()\r
176  * API macro by creating and then deleting counting semaphores with both\r
177  * dynamically and statically allocated semaphore structures.\r
178  */\r
179 static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void );\r
180 \r
181 /*\r
182  * A function that demonstrates and tests the\r
183  * xSemaphoreCreateRecursiveMutexStatic() API macro by creating and then\r
184  * deleting recursive mutexes with both dynamically and statically allocated\r
185  * semaphore structures.\r
186  */\r
187 static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void );\r
188 \r
189 /*\r
190  * Utility function to create pseudo random numbers.\r
191  */\r
192 static UBaseType_t prvRand( void );\r
193 \r
194 /*\r
195  * The task that creates and deletes other tasks has to delay occasionally to\r
196  * ensure lower priority tasks are not starved of processing time.  A pseudo\r
197  * random delay time is used just to add a little bit of randomisation into the\r
198  * execution pattern.  prvGetNextDelayTime() generates the pseudo random delay.\r
199  */\r
200 static TickType_t prvGetNextDelayTime( void );\r
201 \r
202 /*\r
203  * Checks the basic operation of a queue after it has been created.\r
204  */\r
205 static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue );\r
206 \r
207 /*\r
208  * Checks the basic operation of a recursive mutex after it has been created.\r
209  */\r
210 static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore );\r
211 \r
212 /*\r
213  * Checks the basic operation of a binary semaphore after it has been created.\r
214  */\r
215 static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount );\r
216 \r
217 /*\r
218  * Checks the basic operation of an event group after it has been created.\r
219  */\r
220 static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup );\r
221 \r
222 /*-----------------------------------------------------------*/\r
223 \r
224 /* StaticTask_t is a publicly accessible structure that has the same size and\r
225 alignment requirements as the real TCB structure.  It is provided as a mechanism\r
226 for applications to know the size of the TCB (which is dependent on the\r
227 architecture and configuration file settings) without breaking the strict data\r
228 hiding policy by exposing the real TCB.  This StaticTask_t variable is passed\r
229 into the xTaskCreateStatic() function that creates the\r
230 prvStaticallyAllocatedCreator() task, and will hold the TCB of the created\r
231 tasks. */\r
232 static StaticTask_t xCreatorTaskTCBBuffer;\r
233 \r
234 /* This is the stack that will be used by the prvStaticallyAllocatedCreator()\r
235 task, which is itself created using statically allocated buffers (so without any\r
236 dynamic memory allocation). */\r
237 static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ];\r
238 \r
239 /* Used by the pseudo random number generating function. */\r
240 static uint32_t ulNextRand = 0;\r
241 \r
242 /* Used so a check task can ensure this test is still executing, and not\r
243 stalled. */\r
244 static volatile UBaseType_t uxCycleCounter = 0;\r
245 \r
246 /* A variable that gets set to pdTRUE if an error is detected. */\r
247 static volatile BaseType_t xErrorOccurred = pdFALSE;\r
248 \r
249 /*-----------------------------------------------------------*/\r
250 \r
251 void vStartStaticallyAllocatedTasks( void  )\r
252 {\r
253         /* Create a single task, which then repeatedly creates and deletes the\r
254         task implemented by prvStaticallyAllocatedTask() at various different\r
255         priorities, and both with and without statically allocated TCB and stack. */\r
256         xTaskCreateStatic( prvStaticallyAllocatedCreator,               /* The function that implements the task being created. */\r
257                                            "StatCreate",                                                /* Text name for the task - not used by the RTOS, its just to assist debugging. */\r
258                                            staticCREATOR_TASK_STACK_SIZE,               /* Size of the buffer passed in as the stack - in words, not bytes! */\r
259                                            NULL,                                                                /* Parameter passed into the task - not used in this case. */\r
260                                            staticTASK_PRIORITY,                                 /* Priority of the task. */\r
261                                            NULL,                                                                /* Handle of the task being created, not used in this case. */\r
262                                            &( uxCreatorTaskStackBuffer[ 0 ] ),  /* The buffer to use as the task's stack. */\r
263                                            &xCreatorTaskTCBBuffer );                    /* The variable that will hold the task's TCB. */\r
264 \r
265         /* Pseudo seed the random number generator. */\r
266         ulNextRand = ( uint32_t ) prvRand;\r
267 }\r
268 /*-----------------------------------------------------------*/\r
269 \r
270 static void prvStaticallyAllocatedCreator( void *pvParameters )\r
271 {\r
272         /* Avoid compiler warnings. */\r
273         ( void ) pvParameters;\r
274 \r
275         for( ;; )\r
276         {\r
277                 /* Loop, running functions that create and delete the various objects\r
278                 that can be optionally created using either static or dynamic memory\r
279                 allocation. */\r
280                 prvCreateAndDeleteStaticallyAllocatedTasks();\r
281                 prvCreateAndDeleteStaticallyAllocatedQueues();\r
282 \r
283                 /* Ensure lower priority tasks get CPU time. */\r
284                 vTaskDelay( prvGetNextDelayTime() );\r
285 \r
286                 /* Just to show the check task that this task is still executing. */\r
287                 uxCycleCounter++;\r
288 \r
289                 prvCreateAndDeleteStaticallyAllocatedBinarySemaphores();\r
290                 prvCreateAndDeleteStaticallyAllocatedCountingSemaphores();\r
291 \r
292                 vTaskDelay( prvGetNextDelayTime() );\r
293                 uxCycleCounter++;\r
294 \r
295                 prvCreateAndDeleteStaticallyAllocatedMutexes();\r
296                 prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes();\r
297 \r
298                 vTaskDelay( prvGetNextDelayTime() );\r
299                 uxCycleCounter++;\r
300 \r
301                 prvCreateAndDeleteStaticallyAllocatedEventGroups();\r
302                 prvCreateAndDeleteStaticallyAllocatedTimers();\r
303         }\r
304 }\r
305 /*-----------------------------------------------------------*/\r
306 \r
307 static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup )\r
308 {\r
309 EventBits_t xEventBits;\r
310 const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55;\r
311 \r
312         /* The event group should not have any bits set yet. */\r
313         xEventBits = xEventGroupGetBits( xEventGroup );\r
314 \r
315         if( xEventBits != ( EventBits_t ) 0 )\r
316         {\r
317                 xErrorOccurred = pdTRUE;\r
318         }\r
319 \r
320         /* Some some bits, then read them back to check they are as expected. */\r
321         xEventGroupSetBits( xEventGroup, xFirstTestBits );\r
322 \r
323         xEventBits = xEventGroupGetBits( xEventGroup );\r
324 \r
325         if( xEventBits != xFirstTestBits )\r
326         {\r
327                 xErrorOccurred = pdTRUE;\r
328         }\r
329 \r
330         xEventGroupSetBits( xEventGroup, xSecondTestBits );\r
331 \r
332         xEventBits = xEventGroupGetBits( xEventGroup );\r
333 \r
334         if( xEventBits != ( xFirstTestBits | xSecondTestBits ) )\r
335         {\r
336                 xErrorOccurred = pdTRUE;\r
337         }\r
338 \r
339         /* Finally try clearing some bits too and check that operation proceeds as\r
340         expected. */\r
341         xEventGroupClearBits( xEventGroup, xFirstTestBits );\r
342 \r
343         xEventBits = xEventGroupGetBits( xEventGroup );\r
344 \r
345         if( xEventBits != xSecondTestBits )\r
346         {\r
347                 xErrorOccurred = pdTRUE;\r
348         }\r
349 }\r
350 /*-----------------------------------------------------------*/\r
351 \r
352 static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount )\r
353 {\r
354 BaseType_t xReturned;\r
355 UBaseType_t x;\r
356 const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );\r
357 TickType_t xTickCount;\r
358 \r
359         /* The binary semaphore should start 'empty', so a call to xSemaphoreTake()\r
360         should fail. */\r
361         xTickCount = xTaskGetTickCount();\r
362         xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );\r
363 \r
364         if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )\r
365         {\r
366                 /* Did not block on the semaphore as long as expected. */\r
367                 xErrorOccurred = pdTRUE;\r
368         }\r
369 \r
370         if( xReturned != pdFAIL )\r
371         {\r
372                 xErrorOccurred = pdTRUE;\r
373         }\r
374 \r
375         /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount\r
376         times. */\r
377         for( x = 0; x < uxMaxCount; x++ )\r
378         {\r
379                 xReturned = xSemaphoreGive( xSemaphore );\r
380 \r
381                 if( xReturned == pdFAIL )\r
382                 {\r
383                         xErrorOccurred = pdTRUE;\r
384                 }\r
385         }\r
386 \r
387         /* Giving the semaphore again should fail, as it is 'full'. */\r
388         xReturned = xSemaphoreGive( xSemaphore );\r
389 \r
390         if( xReturned != pdFAIL )\r
391         {\r
392                 xErrorOccurred = pdTRUE;\r
393         }\r
394 \r
395         configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );\r
396 \r
397         /* Should now be possible to 'take' the semaphore up to a maximum of\r
398         uxMaxCount times without blocking. */\r
399         for( x = 0; x < uxMaxCount; x++ )\r
400         {\r
401                 xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );\r
402 \r
403                 if( xReturned == pdFAIL )\r
404                 {\r
405                         xErrorOccurred = pdTRUE;\r
406                 }\r
407         }\r
408 \r
409         /* Back to the starting condition, where the semaphore should not be\r
410         available. */\r
411         xTickCount = xTaskGetTickCount();\r
412         xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );\r
413 \r
414         if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )\r
415         {\r
416                 /* Did not block on the semaphore as long as expected. */\r
417                 xErrorOccurred = pdTRUE;\r
418         }\r
419 \r
420         if( xReturned != pdFAIL )\r
421         {\r
422                 xErrorOccurred = pdTRUE;\r
423         }\r
424 \r
425         configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );\r
426 }\r
427 /*-----------------------------------------------------------*/\r
428 \r
429 static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue )\r
430 {\r
431 uint64_t ull, ullRead;\r
432 BaseType_t xReturned, xLoop;\r
433 \r
434         /* This test is done twice to ensure the queue storage area wraps. */\r
435         for( xLoop = 0; xLoop < 2; xLoop++ )\r
436         {\r
437                 /* A very basic test that the queue can be written to and read from as\r
438                 expected.  First the queue should be empty. */\r
439                 xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );\r
440                 if( xReturned != errQUEUE_EMPTY )\r
441                 {\r
442                         xErrorOccurred = pdTRUE;\r
443                 }\r
444 \r
445                 /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS\r
446                 times. */\r
447                 for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )\r
448                 {\r
449                         xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );\r
450                         if( xReturned != pdPASS )\r
451                         {\r
452                                 xErrorOccurred = pdTRUE;\r
453                         }\r
454                 }\r
455 \r
456                 /* Should not now be possible to write to the queue again. */\r
457                 xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );\r
458                 if( xReturned != errQUEUE_FULL )\r
459                 {\r
460                         xErrorOccurred = pdTRUE;\r
461                 }\r
462 \r
463                 /* Now read back from the queue to ensure the data read back matches that\r
464                 written. */\r
465                 for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )\r
466                 {\r
467                         xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );\r
468 \r
469                         if( xReturned != pdPASS )\r
470                         {\r
471                                 xErrorOccurred = pdTRUE;\r
472                         }\r
473 \r
474                         if( ullRead != ull )\r
475                         {\r
476                                 xErrorOccurred = pdTRUE;\r
477                         }\r
478                 }\r
479 \r
480                 /* The queue should be empty again. */\r
481                 xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );\r
482                 if( xReturned != errQUEUE_EMPTY )\r
483                 {\r
484                         xErrorOccurred = pdTRUE;\r
485                 }\r
486         }\r
487 }\r
488 /*-----------------------------------------------------------*/\r
489 \r
490 static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore )\r
491 {\r
492 const BaseType_t xLoops = 5;\r
493 BaseType_t x, xReturned;\r
494 \r
495         /* A very basic test that the recursive semaphore behaved like a recursive\r
496         semaphore. First the semaphore should not be able to be given, as it has not\r
497         yet been taken. */\r
498         xReturned = xSemaphoreGiveRecursive( xSemaphore );\r
499 \r
500         if( xReturned != pdFAIL )\r
501         {\r
502                 xErrorOccurred = pdTRUE;\r
503         }\r
504 \r
505         /* Now it should be possible to take the mutex a number of times. */\r
506         for( x = 0; x < xLoops; x++ )\r
507         {\r
508                 xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK );\r
509 \r
510                 if( xReturned != pdPASS )\r
511                 {\r
512                         xErrorOccurred = pdTRUE;\r
513                 }\r
514         }\r
515 \r
516         /* Should be possible to give the semaphore the same number of times as it\r
517         was given in the loop above. */\r
518         for( x = 0; x < xLoops; x++ )\r
519         {\r
520                 xReturned = xSemaphoreGiveRecursive( xSemaphore );\r
521 \r
522                 if( xReturned != pdPASS )\r
523                 {\r
524                         xErrorOccurred = pdTRUE;\r
525                 }\r
526         }\r
527 \r
528         /* No more gives should be possible though. */\r
529         xReturned = xSemaphoreGiveRecursive( xSemaphore );\r
530 \r
531         if( xReturned != pdFAIL )\r
532         {\r
533                 xErrorOccurred = pdTRUE;\r
534         }\r
535 }\r
536 /*-----------------------------------------------------------*/\r
537 \r
538 static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void )\r
539 {\r
540 SemaphoreHandle_t xSemaphore;\r
541 const UBaseType_t uxMaxCount = ( UBaseType_t ) 10;\r
542 \r
543 /* StaticSemaphore_t is a publicly accessible structure that has the same size\r
544 and alignment requirements as the real semaphore structure.  It is provided as a\r
545 mechanism for applications to know the size of the semaphore (which is dependent\r
546 on the architecture and configuration file settings) without breaking the strict\r
547 data hiding policy by exposing the real semaphore internals.  This\r
548 StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic()\r
549 function calls within this function.  NOTE: In most usage scenarios now it is\r
550 faster and more memory efficient to use a direct to task notification instead of\r
551 a counting semaphore.  http://www.freertos.org/RTOS-task-notifications.html */\r
552 StaticSemaphore_t xSemaphoreBuffer;\r
553 \r
554         /* Create the semaphore.  xSemaphoreCreateCountingStatic() has one more\r
555         parameter than the usual xSemaphoreCreateCounting() function.  The paraemter\r
556         is a pointer to the pre-allocated StaticSemaphore_t structure, which will\r
557         hold information on the semaphore in an anonymous way.  If the pointer is\r
558         passed as NULL then the structure will be allocated dynamically, just as\r
559         when xSemaphoreCreateCounting() is called. */\r
560         xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer );\r
561 \r
562         /* The semaphore handle should equal the static semaphore structure passed\r
563         into the xSemaphoreCreateBinaryStatic() function. */\r
564         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );\r
565 \r
566         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */\r
567         prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );\r
568 \r
569         /* Delete the semaphore again so the buffers can be reused. */\r
570         vSemaphoreDelete( xSemaphore );\r
571 }\r
572 /*-----------------------------------------------------------*/\r
573 \r
574 static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void )\r
575 {\r
576 SemaphoreHandle_t xSemaphore;\r
577 \r
578 /* StaticSemaphore_t is a publicly accessible structure that has the same size\r
579 and alignment requirements as the real semaphore structure.  It is provided as a\r
580 mechanism for applications to know the size of the semaphore (which is dependent\r
581 on the architecture and configuration file settings) without breaking the strict\r
582 data hiding policy by exposing the real semaphore internals.  This\r
583 StaticSemaphore_t variable is passed into the\r
584 xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */\r
585 StaticSemaphore_t xSemaphoreBuffer;\r
586 \r
587         /* Create the semaphore.  xSemaphoreCreateRecursiveMutexStatic() has one\r
588         more parameter than the usual xSemaphoreCreateRecursiveMutex() function.\r
589         The parameter is a pointer to the pre-allocated StaticSemaphore_t structure,\r
590         which will hold information on the semaphore in an anonymous way.  If the\r
591         pointer is passed as NULL then the structure will be allocated dynamically,\r
592         just as when xSemaphoreCreateRecursiveMutex() is called. */\r
593         xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer );\r
594 \r
595         /* The semaphore handle should equal the static semaphore structure passed\r
596         into the xSemaphoreCreateBinaryStatic() function. */\r
597         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );\r
598 \r
599         /* Ensure the semaphore passes a few sanity checks as a valid\r
600         recursive semaphore. */\r
601         prvSanityCheckCreatedRecursiveMutex( xSemaphore );\r
602 \r
603         /* Delete the semaphore again so the buffers can be reused. */\r
604         vSemaphoreDelete( xSemaphore );\r
605 }\r
606 /*-----------------------------------------------------------*/\r
607 \r
608 static void prvCreateAndDeleteStaticallyAllocatedQueues( void )\r
609 {\r
610 QueueHandle_t xQueue;\r
611 \r
612 /* StaticQueue_t is a publicly accessible structure that has the same size and\r
613 alignment requirements as the real queue structure.  It is provided as a\r
614 mechanism for applications to know the size of the queue (which is dependent on\r
615 the architecture and configuration file settings) without breaking the strict\r
616 data hiding policy by exposing the real queue internals.  This StaticQueue_t\r
617 variable is passed into the xQueueCreateStatic() function calls within this\r
618 function. */\r
619 static StaticQueue_t xStaticQueue;\r
620 \r
621 /* The queue storage area must be large enough to hold the maximum number of\r
622 items it is possible for the queue to hold at any one time, which equals the\r
623 queue length (in items, not bytes) multiplied by the size of each item.  In this\r
624 case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items.  See\r
625 http://www.freertos.org/Embedded-RTOS-Queues.html */\r
626 static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];\r
627 \r
628         /* Create the queue.  xQueueCreateStatic() has two more parameters than the\r
629         usual xQueueCreate() function.  The first new parameter is a pointer to the\r
630         pre-allocated queue storage area.  The second new parameter is a pointer to\r
631         the StaticQueue_t structure that will hold the queue state information in\r
632         an anonymous way.  If the two pointers are passed as NULL then the data\r
633         will be allocated dynamically as if xQueueCreate() had been called. */\r
634         xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */\r
635                                                                  sizeof( uint64_t ), /* The size of each item. */\r
636                                                                  ucQueueStorageArea, /* The buffer used to hold items within the queue. */\r
637                                                                  &xStaticQueue );        /* The static queue structure that will hold the state of the queue. */\r
638 \r
639         /* The queue handle should equal the static queue structure passed into the\r
640         xQueueCreateStatic() function. */\r
641         configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );\r
642 \r
643         /* Ensure the queue passes a few sanity checks as a valid queue. */\r
644         prvSanityCheckCreatedQueue( xQueue );\r
645 \r
646         /* Delete the queue again so the buffers can be reused. */\r
647         vQueueDelete( xQueue );\r
648 }\r
649 /*-----------------------------------------------------------*/\r
650 \r
651 static void prvCreateAndDeleteStaticallyAllocatedMutexes( void )\r
652 {\r
653 SemaphoreHandle_t xSemaphore;\r
654 BaseType_t xReturned;\r
655 \r
656 /* StaticSemaphore_t is a publicly accessible structure that has the same size\r
657 and alignment requirements as the real semaphore structure.  It is provided as a\r
658 mechanism for applications to know the size of the semaphore (which is dependent\r
659 on the architecture and configuration file settings) without breaking the strict\r
660 data hiding policy by exposing the real semaphore internals.  This\r
661 StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic()\r
662 function calls within this function. */\r
663 StaticSemaphore_t xSemaphoreBuffer;\r
664 \r
665         /* Create the semaphore.  xSemaphoreCreateMutexStatic() has one more\r
666         parameter than the usual xSemaphoreCreateMutex() function.  The paraemter\r
667         is a pointer to the pre-allocated StaticSemaphore_t structure, which will\r
668         hold information on the semaphore in an anonymous way.  If the pointer is\r
669         passed as NULL then the structure will be allocated dynamically, just as\r
670         when xSemaphoreCreateMutex() is called. */\r
671         xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer );\r
672 \r
673         /* The semaphore handle should equal the static semaphore structure passed\r
674         into the xSemaphoreCreateMutexStatic() function. */\r
675         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );\r
676 \r
677         /* Take the mutex so the mutex is in the state expected by the\r
678         prvSanityCheckCreatedSemaphore() function. */\r
679         xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );\r
680 \r
681         if( xReturned != pdPASS )\r
682         {\r
683                 xErrorOccurred = pdTRUE;\r
684         }\r
685 \r
686         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */\r
687         prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );\r
688 \r
689         /* Delete the semaphore again so the buffers can be reused. */\r
690         vSemaphoreDelete( xSemaphore );\r
691 }\r
692 /*-----------------------------------------------------------*/\r
693 \r
694 static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )\r
695 {\r
696 SemaphoreHandle_t xSemaphore;\r
697 \r
698 /* StaticSemaphore_t is a publicly accessible structure that has the same size\r
699 and alignment requirements as the real semaphore structure.  It is provided as a\r
700 mechanism for applications to know the size of the semaphore (which is dependent\r
701 on the architecture and configuration file settings) without breaking the strict\r
702 data hiding policy by exposing the real semaphore internals.  This\r
703 StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic()\r
704 function calls within this function.  NOTE: In most usage scenarios now it is\r
705 faster and more memory efficient to use a direct to task notification instead of\r
706 a binary semaphore.  http://www.freertos.org/RTOS-task-notifications.html */\r
707 StaticSemaphore_t xSemaphoreBuffer;\r
708 \r
709         /* Create the semaphore.  xSemaphoreCreateBinaryStatic() has one more\r
710         parameter than the usual xSemaphoreCreateBinary() function.  The paraemter\r
711         is a pointer to the pre-allocated StaticSemaphore_t structure, which will\r
712         hold information on the semaphore in an anonymous way.  If the pointer is\r
713         passed as NULL then the structure will be allocated dynamically, just as\r
714         when xSemaphoreCreateBinary() is called. */\r
715         xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );\r
716 \r
717         /* The semaphore handle should equal the static semaphore structure passed\r
718         into the xSemaphoreCreateBinaryStatic() function. */\r
719         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );\r
720 \r
721         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */\r
722         prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );\r
723 \r
724         /* Delete the semaphore again so the buffers can be reused. */\r
725         vSemaphoreDelete( xSemaphore );\r
726 \r
727 \r
728         /* There isn't a static version of the old and deprecated\r
729         vSemaphoreCreateBinary() macro (because its deprecated!), but check it is\r
730         still functioning correctly when configSUPPORT_STATIC_ALLOCATION is set to\r
731         1. */\r
732         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
733         {\r
734                 vSemaphoreCreateBinary( xSemaphore );\r
735 \r
736                 /* The macro starts with the binary semaphore available, but the test\r
737                 function expects it to be unavailable. */\r
738                 if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )\r
739                 {\r
740                         xErrorOccurred = pdTRUE;\r
741                 }\r
742 \r
743                 prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );\r
744                 vSemaphoreDelete( xSemaphore );\r
745         }\r
746         #endif\r
747 }\r
748 /*-----------------------------------------------------------*/\r
749 \r
750 static void prvTimerCallback( TimerHandle_t xExpiredTimer )\r
751 {\r
752 UBaseType_t *puxVariableToIncrement;\r
753 BaseType_t xReturned;\r
754 \r
755         /* Obtain the address of the variable to increment from the timer ID. */\r
756         puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );\r
757 \r
758         /* Increment the variable to show the timer callback has executed. */\r
759         ( *puxVariableToIncrement )++;\r
760 \r
761         /* If this callback has executed the required number of times, stop the\r
762         timer. */\r
763         if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS )\r
764         {\r
765                 /* This is called from a timer callback so must not block. */\r
766                 xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK );\r
767 \r
768                 if( xReturned != pdPASS )\r
769                 {\r
770                         xErrorOccurred = pdTRUE;\r
771                 }\r
772         }\r
773 }\r
774 /*-----------------------------------------------------------*/\r
775 \r
776 static void prvCreateAndDeleteStaticallyAllocatedTimers( void )\r
777 {\r
778 TimerHandle_t xTimer;\r
779 UBaseType_t uxVariableToIncrement;\r
780 const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 );\r
781 BaseType_t xReturned;\r
782 \r
783 /* StaticTimer_t is a publicly accessible structure that has the same size\r
784 and alignment requirements as the real timer structure.  It is provided as a\r
785 mechanism for applications to know the size of the timer structure (which is\r
786 dependent on the architecture and configuration file settings) without breaking\r
787 the strict data hiding policy by exposing the real timer internals.  This\r
788 StaticTimer_t variable is passed into the xTimerCreateStatic() function calls\r
789 within this function. */\r
790 StaticTimer_t xTimerBuffer;\r
791 \r
792         /* Create the software time.  xTimerCreateStatic() has an extra parameter\r
793         than the normal xTimerCreate() API function.  The parameter is a pointer to\r
794         the StaticTimer_t structure that will hold the software timer structure.  If\r
795         the parameter is passed as NULL then the structure will be allocated\r
796         dynamically, just as if xTimerCreate() had been called. */\r
797         xTimer = xTimerCreateStatic( "T1",                                      /* Text name for the task.  Helps debugging only.  Not used by FreeRTOS. */\r
798                                                                  xTimerPeriod,                  /* The period of the timer in ticks. */\r
799                                                                  pdTRUE,                                /* This is an auto-reload timer. */\r
800                                                                  ( void * ) &uxVariableToIncrement,     /* The variable incremented by the test is passed into the timer callback using the timer ID. */\r
801                                                                  prvTimerCallback,              /* The function to execute when the timer expires. */\r
802                                                                  &xTimerBuffer );               /* The buffer that will hold the software timer structure. */\r
803 \r
804         /* The timer handle should equal the static timer structure passed into the\r
805         xTimerCreateStatic() function. */\r
806         configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer );\r
807 \r
808         /* Set the variable to 0, wait for a few timer periods to expire, then check\r
809         the timer callback has incremented the variable to the expected value. */\r
810         uxVariableToIncrement = 0;\r
811 \r
812         /* This is a low priority so a block time should not be needed. */\r
813         xReturned = xTimerStart( xTimer, staticDONT_BLOCK );\r
814 \r
815         if( xReturned != pdPASS )\r
816         {\r
817                 xErrorOccurred = pdTRUE;\r
818         }\r
819 \r
820         vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );\r
821 \r
822         /* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS\r
823         times, and then stopped itself. */\r
824         if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )\r
825         {\r
826                 xErrorOccurred = pdTRUE;\r
827         }\r
828 \r
829         /* Finished with the timer, delete it. */\r
830         xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );\r
831 \r
832         /* Again, as this is a low priority task it is expected that the timer\r
833         command will have been sent even without a block time being used. */\r
834         if( xReturned != pdPASS )\r
835         {\r
836                 xErrorOccurred = pdTRUE;\r
837         }\r
838 \r
839         /* Just to show the check task that this task is still executing. */\r
840         uxCycleCounter++;\r
841 }\r
842 /*-----------------------------------------------------------*/\r
843 \r
844 static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void )\r
845 {\r
846 EventGroupHandle_t xEventGroup;\r
847 \r
848 /* StaticEventGroup_t is a publicly accessible structure that has the same size\r
849 and alignment requirements as the real event group structure.  It is provided as\r
850 a mechanism for applications to know the size of the event group (which is\r
851 dependent on the architecture and configuration file settings) without breaking\r
852 the strict data hiding policy by exposing the real event group internals.  This\r
853 StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic()\r
854 function calls within this function. */\r
855 StaticEventGroup_t xEventGroupBuffer;\r
856 \r
857         /* Create the event group.  xEventGroupCreateStatic() has an extra parameter\r
858         than the normal xEventGroupCreate() API function.  The parameter is a\r
859         pointer to the StaticEventGroup_t structure that will hold the event group\r
860         structure.  If the parameter is passed as NULL then the structure will be\r
861         allocated dynamically, just as if xEventGroupCreate() had been called. */\r
862         xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );\r
863 \r
864         /* The event group handle should equal the static event group structure\r
865         passed into the xEventGroupCreateStatic() function. */\r
866         configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer );\r
867 \r
868         /* Ensure the event group passes a few sanity checks as a valid event\r
869         group. */\r
870         prvSanityCheckCreatedEventGroup( xEventGroup );\r
871 \r
872         /* Delete the event group again so the buffers can be reused. */\r
873         vEventGroupDelete( xEventGroup );\r
874 }\r
875 /*-----------------------------------------------------------*/\r
876 \r
877 static void prvCreateAndDeleteStaticallyAllocatedTasks( void )\r
878 {\r
879 TaskHandle_t xCreatedTask;\r
880 BaseType_t xReturned;\r
881 \r
882 /* The variable that will hold the TCB of tasks created by this function.  See\r
883 the comments above the declaration of the xCreatorTaskTCBBuffer variable for\r
884 more information. */\r
885 StaticTask_t xTCBBuffer;\r
886 \r
887 /* This buffer that will be used as the stack of tasks created by this function.\r
888 See the comments above the declaration of the uxCreatorTaskStackBuffer[] array\r
889 above for more information. */\r
890 static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];\r
891 \r
892         /* Create the task.  xTaskCreateStatic() has two more parameters than\r
893         the usual xTaskCreate() function.  The first new parameter is a pointer to\r
894         the pre-allocated stack.  The second new parameter is a pointer to the\r
895         StaticTask_t structure that will hold the task's TCB.  If both pointers are\r
896         passed as NULL then the respective object will be allocated dynamically as\r
897         if xTaskCreate() had been called. */\r
898         xReturned = xTaskCreateStatic(\r
899                                                 prvStaticallyAllocatedTask, /* Function that implements the task. */\r
900                                                 "Static",                                       /* Human readable name for the task. */\r
901                                                 configMINIMAL_STACK_SIZE,       /* Task's stack size, in words (not bytes!). */\r
902                                                 NULL,                                           /* Parameter to pass into the task. */\r
903                                                 tskIDLE_PRIORITY,                       /* The priority of the task. */\r
904                                                 &xCreatedTask,                          /* Handle of the task being created. */\r
905                                                 &( uxStackBuffer[ 0 ] ),        /* The buffer to use as the task's stack. */\r
906                                                 &xTCBBuffer );                          /* The variable that will hold that task's TCB. */\r
907 \r
908         /* Check the task was created correctly, then delete the task. */\r
909         configASSERT( xReturned == pdPASS );\r
910         if( xReturned != pdPASS )\r
911         {\r
912                 xErrorOccurred = pdTRUE;\r
913         }\r
914         vTaskDelete( xCreatedTask );\r
915 }\r
916 /*-----------------------------------------------------------*/\r
917 \r
918 static void prvStaticallyAllocatedTask( void *pvParameters )\r
919 {\r
920         ( void ) pvParameters;\r
921 \r
922         /* The created task doesn't do anything - just waits to get deleted. */\r
923         vTaskSuspend( NULL );\r
924 }\r
925 /*-----------------------------------------------------------*/\r
926 \r
927 static UBaseType_t prvRand( void )\r
928 {\r
929 const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;\r
930 \r
931         /* Utility function to generate a pseudo random number. */\r
932         ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;\r
933         return( ( ulNextRand >> 16UL ) & 0x7fffUL );\r
934 }\r
935 /*-----------------------------------------------------------*/\r
936 \r
937 static TickType_t prvGetNextDelayTime( void )\r
938 {\r
939 TickType_t xNextDelay;\r
940 const TickType_t xMaxDelay = pdMS_TO_TICKS( ( TickType_t ) 150 );\r
941 const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 );\r
942 const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 );\r
943 \r
944         /* Generate the next delay time.  This is kept within a narrow band so as\r
945         not to disturb the timing of other tests - but does add in some pseudo\r
946         randomisation into the tests. */\r
947         do\r
948         {\r
949                 xNextDelay = prvRand() % xMaxDelay;\r
950 \r
951                 /* Just in case this loop is executed lots of times. */\r
952                 vTaskDelay( xTinyDelay );\r
953 \r
954         } while ( xNextDelay < xMinDelay );\r
955 \r
956         return xNextDelay;\r
957 }\r
958 /*-----------------------------------------------------------*/\r
959 \r
960 BaseType_t xAreStaticAllocationTasksStillRunning( void )\r
961 {\r
962 static UBaseType_t uxLastCycleCounter = 0;\r
963 BaseType_t xReturn;\r
964 \r
965         if( uxCycleCounter == uxLastCycleCounter )\r
966         {\r
967                 xErrorOccurred = pdTRUE;\r
968         }\r
969         else\r
970         {\r
971                 uxLastCycleCounter = uxCycleCounter;\r
972         }\r
973 \r
974         if( xErrorOccurred != pdFALSE )\r
975         {\r
976                 xReturn = pdFAIL;\r
977         }\r
978         else\r
979         {\r
980                 xReturn = pdPASS;\r
981         }\r
982 \r
983         return xReturn;\r
984 }\r
985 /*-----------------------------------------------------------*/\r
986 \r
987 /* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */\r
988 #endif /* configSUPPORT_STATIC_ALLOCATION == 1 */\r