]> begriffs open source - cmsis-freertos/blob - Demo/Common/Minimal/StaticAllocation.c
Updated pack to FreeRTOS 10.3.1
[cmsis-freertos] / Demo / Common / Minimal / StaticAllocation.c
1 /*
2  * FreeRTOS Kernel V10.3.1
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28
29 /*
30  * Demonstrates how to create FreeRTOS objects using pre-allocated memory,
31  * rather than the normal dynamically allocated memory, and tests objects being
32  * created and deleted with both statically allocated memory and dynamically
33  * allocated memory.
34  *
35  * See http://www.FreeRTOS.org/Static_Vs_Dynamic_Memory_Allocation.html
36  */
37
38 /* Scheduler include files. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43 #include "event_groups.h"
44 #include "timers.h"
45
46 /* Demo program include files. */
47 #include "StaticAllocation.h"
48
49 /* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
50 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
51
52 /* The priority at which the task that performs the tests is created. */
53 #define staticTASK_PRIORITY                                     ( tskIDLE_PRIORITY + 2 )
54
55 /* The length of the queue, in items, not bytes, used in the queue static
56 allocation tests. */
57 #define staticQUEUE_LENGTH_IN_ITEMS                     ( 5 )
58
59 /* A block time of 0 simply means "don't block". */
60 #define staticDONT_BLOCK                                        ( ( TickType_t ) 0 )
61
62 /* Binary semaphores have a maximum count of 1. */
63 #define staticBINARY_SEMAPHORE_MAX_COUNT        ( 1 )
64
65 /* The size of the stack used by the task that runs the tests. */
66 #define staticCREATOR_TASK_STACK_SIZE           ( configMINIMAL_STACK_SIZE * 2 )
67
68 /* The number of times the software timer will execute before stopping itself. */
69 #define staticMAX_TIMER_CALLBACK_EXECUTIONS     ( 5 )
70
71
72 /*-----------------------------------------------------------*/
73
74 /*
75  * The task that repeatedly creates and deletes statically allocated tasks, and
76  * other RTOS objects.
77  */
78 static void prvStaticallyAllocatedCreator( void *pvParameters );
79
80 /*
81  * The callback function used by the software timer that is repeatedly created
82  * and deleted using both static and dynamically allocated memory.
83  */
84 static void prvTimerCallback( TimerHandle_t xExpiredTimer );
85
86 /*
87  * A task that is created and deleted multiple times, using both statically and
88  * dynamically allocated stack and TCB.
89  */
90 static void prvStaticallyAllocatedTask( void *pvParameters );
91
92 /*
93  * A function that demonstrates and tests the API functions that create and
94  * delete tasks using both statically and dynamically allocated TCBs and stacks.
95  */
96 static void prvCreateAndDeleteStaticallyAllocatedTasks( void );
97
98 /*
99  * A function that demonstrates and tests the API functions that create and
100  * delete event groups using both statically and dynamically allocated RAM.
101  */
102 static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void );
103
104 /*
105  * A function that demonstrates and tests the API functions that create and
106  * delete queues using both statically and dynamically allocated RAM.
107  */
108 static void prvCreateAndDeleteStaticallyAllocatedQueues( void );
109
110 /*
111  * A function that demonstrates and tests the API functions that create and
112  * delete binary semaphores using both statically and dynamically allocated RAM.
113  */
114 static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void );
115
116 /*
117  * A function that demonstrates and tests the API functions that create and
118  * delete software timers using both statically and dynamically allocated RAM.
119  */
120 static void prvCreateAndDeleteStaticallyAllocatedTimers( void );
121
122 /*
123  * A function that demonstrates and tests the API functions that create and
124  * delete mutexes using both statically and dynamically allocated RAM.
125  */
126 static void prvCreateAndDeleteStaticallyAllocatedMutexes( void );
127
128 /*
129  * A function that demonstrates and tests the API functions that create and
130  * delete counting semaphores using both statically and dynamically allocated
131  * RAM.
132  */
133 static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void );
134
135 /*
136  * A function that demonstrates and tests the API functions that create and
137  * delete recursive mutexes using both statically and dynamically allocated RAM.
138  */
139 static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void );
140
141 /*
142  * Utility function to create pseudo random numbers.
143  */
144 static UBaseType_t prvRand( void );
145
146 /*
147  * The task that creates and deletes other tasks has to delay occasionally to
148  * ensure lower priority tasks are not starved of processing time.  A pseudo
149  * random delay time is used just to add a little bit of randomisation into the
150  * execution pattern.  prvGetNextDelayTime() generates the pseudo random delay.
151  */
152 static TickType_t prvGetNextDelayTime( void );
153
154 /*
155  * Checks the basic operation of a queue after it has been created.
156  */
157 static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue );
158
159 /*
160  * Checks the basic operation of a recursive mutex after it has been created.
161  */
162 static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore );
163
164 /*
165  * Checks the basic operation of a binary semaphore after it has been created.
166  */
167 static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount );
168
169 /*
170  * Checks the basic operation of an event group after it has been created.
171  */
172 static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup );
173
174 /*-----------------------------------------------------------*/
175
176 /* StaticTask_t is a publicly accessible structure that has the same size and
177 alignment requirements as the real TCB structure.  It is provided as a mechanism
178 for applications to know the size of the TCB (which is dependent on the
179 architecture and configuration file settings) without breaking the strict data
180 hiding policy by exposing the real TCB.  This StaticTask_t variable is passed
181 into the xTaskCreateStatic() function that creates the
182 prvStaticallyAllocatedCreator() task, and will hold the TCB of the created
183 tasks. */
184 static StaticTask_t xCreatorTaskTCBBuffer;
185
186 /* This is the stack that will be used by the prvStaticallyAllocatedCreator()
187 task, which is itself created using statically allocated buffers (so without any
188 dynamic memory allocation). */
189 static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ];
190
191 /* Used by the pseudo random number generating function. */
192 static uint32_t ulNextRand = 0;
193
194 /* Used so a check task can ensure this test is still executing, and not
195 stalled. */
196 static volatile UBaseType_t uxCycleCounter = 0;
197
198 /* A variable that gets set to pdTRUE if an error is detected. */
199 static volatile BaseType_t xErrorOccurred = pdFALSE;
200
201 /*-----------------------------------------------------------*/
202
203 void vStartStaticallyAllocatedTasks( void  )
204 {
205         /* Create a single task, which then repeatedly creates and deletes the other
206         RTOS objects using both statically and dynamically allocated RAM. */
207         xTaskCreateStatic( prvStaticallyAllocatedCreator,               /* The function that implements the task being created. */
208                                            "StatCreate",                                                /* Text name for the task - not used by the RTOS, its just to assist debugging. */
209                                            staticCREATOR_TASK_STACK_SIZE,               /* Size of the buffer passed in as the stack - in words, not bytes! */
210                                            NULL,                                                                /* Parameter passed into the task - not used in this case. */
211                                            staticTASK_PRIORITY,                                 /* Priority of the task. */
212                                            &( uxCreatorTaskStackBuffer[ 0 ] ),  /* The buffer to use as the task's stack. */
213                                            &xCreatorTaskTCBBuffer );                    /* The variable that will hold the task's TCB. */
214 }
215 /*-----------------------------------------------------------*/
216
217 static void prvStaticallyAllocatedCreator( void *pvParameters )
218 {
219         /* Avoid compiler warnings. */
220         ( void ) pvParameters;
221
222         for( ;; )
223         {
224                 /* Loop, running functions that create and delete the various RTOS
225                 objects that can be optionally created using either static or dynamic
226                 memory allocation. */
227                 prvCreateAndDeleteStaticallyAllocatedTasks();
228                 prvCreateAndDeleteStaticallyAllocatedQueues();
229
230                 /* Delay to ensure lower priority tasks get CPU time, and increment the
231                 cycle counter so a 'check' task can determine that this task is still
232                 executing. */
233                 vTaskDelay( prvGetNextDelayTime() );
234                 uxCycleCounter++;
235
236                 prvCreateAndDeleteStaticallyAllocatedBinarySemaphores();
237                 prvCreateAndDeleteStaticallyAllocatedCountingSemaphores();
238
239                 vTaskDelay( prvGetNextDelayTime() );
240                 uxCycleCounter++;
241
242                 prvCreateAndDeleteStaticallyAllocatedMutexes();
243                 prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes();
244
245                 vTaskDelay( prvGetNextDelayTime() );
246                 uxCycleCounter++;
247
248                 prvCreateAndDeleteStaticallyAllocatedEventGroups();
249                 prvCreateAndDeleteStaticallyAllocatedTimers();
250         }
251 }
252 /*-----------------------------------------------------------*/
253
254 static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void )
255 {
256 SemaphoreHandle_t xSemaphore;
257 const UBaseType_t uxMaxCount = ( UBaseType_t ) 10;
258
259 /* StaticSemaphore_t is a publicly accessible structure that has the same size
260 and alignment requirements as the real semaphore structure.  It is provided as a
261 mechanism for applications to know the size of the semaphore (which is dependent
262 on the architecture and configuration file settings) without breaking the strict
263 data hiding policy by exposing the real semaphore internals.  This
264 StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic()
265 function calls within this function.  NOTE: In most usage scenarios now it is
266 faster and more memory efficient to use a direct to task notification instead of
267 a counting semaphore.  http://www.freertos.org/RTOS-task-notifications.html */
268 StaticSemaphore_t xSemaphoreBuffer;
269
270         /* Create the semaphore.  xSemaphoreCreateCountingStatic() has one more
271         parameter than the usual xSemaphoreCreateCounting() function.  The parameter
272         is a pointer to the pre-allocated StaticSemaphore_t structure, which will
273         hold information on the semaphore in an anonymous way.  If the pointer is
274         passed as NULL then the structure will be allocated dynamically, just as
275         when xSemaphoreCreateCounting() is called. */
276         xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer );
277
278         /* The semaphore handle should equal the static semaphore structure passed
279         into the xSemaphoreCreateBinaryStatic() function. */
280         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
281
282         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
283         prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
284
285         /* Delete the semaphore again so the buffers can be reused. */
286         vSemaphoreDelete( xSemaphore );
287
288         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
289         {
290                 /* Now do the same but using dynamically allocated buffers to ensure the
291                 delete functions are working correctly in both the static and dynamic
292                 allocation cases. */
293                 xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 );
294                 configASSERT( xSemaphore != NULL );
295                 prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
296                 vSemaphoreDelete( xSemaphore );
297         }
298         #endif
299 }
300 /*-----------------------------------------------------------*/
301
302 static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void )
303 {
304 SemaphoreHandle_t xSemaphore;
305
306 /* StaticSemaphore_t is a publicly accessible structure that has the same size
307 and alignment requirements as the real semaphore structure.  It is provided as a
308 mechanism for applications to know the size of the semaphore (which is dependent
309 on the architecture and configuration file settings) without breaking the strict
310 data hiding policy by exposing the real semaphore internals.  This
311 StaticSemaphore_t variable is passed into the
312 xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */
313 StaticSemaphore_t xSemaphoreBuffer;
314
315         /* Create the semaphore.  xSemaphoreCreateRecursiveMutexStatic() has one
316         more parameter than the usual xSemaphoreCreateRecursiveMutex() function.
317         The parameter is a pointer to the pre-allocated StaticSemaphore_t structure,
318         which will hold information on the semaphore in an anonymous way.  If the
319         pointer is passed as NULL then the structure will be allocated dynamically,
320         just as when xSemaphoreCreateRecursiveMutex() is called. */
321         xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer );
322
323         /* The semaphore handle should equal the static semaphore structure passed
324         into the xSemaphoreCreateBinaryStatic() function. */
325         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
326
327         /* Ensure the semaphore passes a few sanity checks as a valid
328         recursive semaphore. */
329         prvSanityCheckCreatedRecursiveMutex( xSemaphore );
330
331         /* Delete the semaphore again so the buffers can be reused. */
332         vSemaphoreDelete( xSemaphore );
333
334         /* Now do the same using dynamically allocated buffers to ensure the delete
335         functions are working correctly in both the static and dynamic memory
336         allocation cases. */
337         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
338         {
339                 xSemaphore = xSemaphoreCreateRecursiveMutex();
340                 configASSERT( xSemaphore != NULL );
341                 prvSanityCheckCreatedRecursiveMutex( xSemaphore );
342                 vSemaphoreDelete( xSemaphore );
343         }
344         #endif
345 }
346 /*-----------------------------------------------------------*/
347
348 static void prvCreateAndDeleteStaticallyAllocatedQueues( void )
349 {
350 QueueHandle_t xQueue;
351
352 /* StaticQueue_t is a publicly accessible structure that has the same size and
353 alignment requirements as the real queue structure.  It is provided as a
354 mechanism for applications to know the size of the queue (which is dependent on
355 the architecture and configuration file settings) without breaking the strict
356 data hiding policy by exposing the real queue internals.  This StaticQueue_t
357 variable is passed into the xQueueCreateStatic() function calls within this
358 function. */
359 static StaticQueue_t xStaticQueue;
360
361 /* The queue storage area must be large enough to hold the maximum number of
362 items it is possible for the queue to hold at any one time, which equals the
363 queue length (in items, not bytes) multiplied by the size of each item.  In this
364 case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items.  See
365 http://www.freertos.org/Embedded-RTOS-Queues.html */
366 static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];
367
368         /* Create the queue.  xQueueCreateStatic() has two more parameters than the
369         usual xQueueCreate() function.  The first new parameter is a pointer to the
370         pre-allocated queue storage area.  The second new parameter is a pointer to
371         the StaticQueue_t structure that will hold the queue state information in
372         an anonymous way.  If the two pointers are passed as NULL then the data
373         will be allocated dynamically as if xQueueCreate() had been called. */
374         xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
375                                                                  sizeof( uint64_t ), /* The size of each item. */
376                                                                  ucQueueStorageArea, /* The buffer used to hold items within the queue. */
377                                                                  &xStaticQueue );        /* The static queue structure that will hold the state of the queue. */
378
379         /* The queue handle should equal the static queue structure passed into the
380         xQueueCreateStatic() function. */
381         configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
382
383         /* Ensure the queue passes a few sanity checks as a valid queue. */
384         prvSanityCheckCreatedQueue( xQueue );
385
386         /* Delete the queue again so the buffers can be reused. */
387         vQueueDelete( xQueue );
388
389         /* Now do the same using a dynamically allocated queue to ensure the delete
390         function is working correctly in both the static and dynamic memory
391         allocation cases. */
392         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
393         {
394                 xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
395                                                            sizeof( uint64_t ) );                /* The size of each item. */
396
397                 /* The queue handle should equal the static queue structure passed into the
398                 xQueueCreateStatic() function. */
399                 configASSERT( xQueue != NULL );
400
401                 /* Ensure the queue passes a few sanity checks as a valid queue. */
402                 prvSanityCheckCreatedQueue( xQueue );
403
404                 /* Delete the queue again so the buffers can be reused. */
405                 vQueueDelete( xQueue );
406         }
407         #endif
408 }
409 /*-----------------------------------------------------------*/
410
411 static void prvCreateAndDeleteStaticallyAllocatedMutexes( void )
412 {
413 SemaphoreHandle_t xSemaphore;
414 BaseType_t xReturned;
415
416 /* StaticSemaphore_t is a publicly accessible structure that has the same size
417 and alignment requirements as the real semaphore structure.  It is provided as a
418 mechanism for applications to know the size of the semaphore (which is dependent
419 on the architecture and configuration file settings) without breaking the strict
420 data hiding policy by exposing the real semaphore internals.  This
421 StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic()
422 function calls within this function. */
423 StaticSemaphore_t xSemaphoreBuffer;
424
425         /* Create the semaphore.  xSemaphoreCreateMutexStatic() has one more
426         parameter than the usual xSemaphoreCreateMutex() function.  The parameter
427         is a pointer to the pre-allocated StaticSemaphore_t structure, which will
428         hold information on the semaphore in an anonymous way.  If the pointer is
429         passed as NULL then the structure will be allocated dynamically, just as
430         when xSemaphoreCreateMutex() is called. */
431         xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer );
432
433         /* The semaphore handle should equal the static semaphore structure passed
434         into the xSemaphoreCreateMutexStatic() function. */
435         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
436
437         /* Take the mutex so the mutex is in the state expected by the
438         prvSanityCheckCreatedSemaphore() function. */
439         xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
440
441         if( xReturned != pdPASS )
442         {
443                 xErrorOccurred = pdTRUE;
444         }
445
446         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
447         prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
448
449         /* Delete the semaphore again so the buffers can be reused. */
450         vSemaphoreDelete( xSemaphore );
451
452         /* Now do the same using a dynamically allocated mutex to ensure the delete
453         function is working correctly in both the static and dynamic allocation
454         cases. */
455         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
456         {
457                 xSemaphore = xSemaphoreCreateMutex();
458
459                 /* The semaphore handle should equal the static semaphore structure
460                 passed into the xSemaphoreCreateMutexStatic() function. */
461                 configASSERT( xSemaphore != NULL );
462
463                 /* Take the mutex so the mutex is in the state expected by the
464                 prvSanityCheckCreatedSemaphore() function. */
465                 xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
466
467                 if( xReturned != pdPASS )
468                 {
469                         xErrorOccurred = pdTRUE;
470                 }
471
472                 /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
473                 prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
474
475                 /* Delete the semaphore again so the buffers can be reused. */
476                 vSemaphoreDelete( xSemaphore );
477         }
478         #endif
479 }
480 /*-----------------------------------------------------------*/
481
482 static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )
483 {
484 SemaphoreHandle_t xSemaphore;
485
486 /* StaticSemaphore_t is a publicly accessible structure that has the same size
487 and alignment requirements as the real semaphore structure.  It is provided as a
488 mechanism for applications to know the size of the semaphore (which is dependent
489 on the architecture and configuration file settings) without breaking the strict
490 data hiding policy by exposing the real semaphore internals.  This
491 StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic()
492 function calls within this function.  NOTE: In most usage scenarios now it is
493 faster and more memory efficient to use a direct to task notification instead of
494 a binary semaphore.  http://www.freertos.org/RTOS-task-notifications.html */
495 StaticSemaphore_t xSemaphoreBuffer;
496
497         /* Create the semaphore.  xSemaphoreCreateBinaryStatic() has one more
498         parameter than the usual xSemaphoreCreateBinary() function.  The parameter
499         is a pointer to the pre-allocated StaticSemaphore_t structure, which will
500         hold information on the semaphore in an anonymous way.  If the pointer is
501         passed as NULL then the structure will be allocated dynamically, just as
502         when xSemaphoreCreateBinary() is called. */
503         xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
504
505         /* The semaphore handle should equal the static semaphore structure passed
506         into the xSemaphoreCreateBinaryStatic() function. */
507         configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
508
509         /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
510         prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
511
512         /* Delete the semaphore again so the buffers can be reused. */
513         vSemaphoreDelete( xSemaphore );
514
515         /* Now do the same using a dynamically allocated semaphore to check the
516         delete function is working correctly in both the static and dynamic
517         allocation cases. */
518         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
519         {
520                 xSemaphore = xSemaphoreCreateBinary();
521                 configASSERT( xSemaphore != NULL );
522                 prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
523                 vSemaphoreDelete( xSemaphore );
524         }
525         #endif
526
527         /* There isn't a static version of the old and deprecated
528         vSemaphoreCreateBinary() macro (because its deprecated!), but check it is
529         still functioning correctly. */
530         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
531         {
532                 vSemaphoreCreateBinary( xSemaphore );
533
534                 /* The macro starts with the binary semaphore available, but the test
535                 function expects it to be unavailable. */
536                 if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )
537                 {
538                         xErrorOccurred = pdTRUE;
539                 }
540
541                 prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
542                 vSemaphoreDelete( xSemaphore );
543         }
544         #endif
545 }
546 /*-----------------------------------------------------------*/
547
548 static void prvTimerCallback( TimerHandle_t xExpiredTimer )
549 {
550 UBaseType_t *puxVariableToIncrement;
551 BaseType_t xReturned;
552
553         /* The timer callback just demonstrates it is executing by incrementing a
554         variable - the address of which is passed into the timer as its ID.  Obtain
555         the address of the variable to increment. */
556         puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );
557
558         /* Increment the variable to show the timer callback has executed. */
559         ( *puxVariableToIncrement )++;
560
561         /* If this callback has executed the required number of times, stop the
562         timer. */
563         if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS )
564         {
565                 /* This is called from a timer callback so must not block.  See
566                 http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */
567                 xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK );
568
569                 if( xReturned != pdPASS )
570                 {
571                         xErrorOccurred = pdTRUE;
572                 }
573         }
574 }
575 /*-----------------------------------------------------------*/
576
577 static void prvCreateAndDeleteStaticallyAllocatedTimers( void )
578 {
579 TimerHandle_t xTimer;
580 UBaseType_t uxVariableToIncrement;
581 const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 );
582 BaseType_t xReturned;
583
584 /* StaticTimer_t is a publicly accessible structure that has the same size
585 and alignment requirements as the real timer structure.  It is provided as a
586 mechanism for applications to know the size of the timer structure (which is
587 dependent on the architecture and configuration file settings) without breaking
588 the strict data hiding policy by exposing the real timer internals.  This
589 StaticTimer_t variable is passed into the xTimerCreateStatic() function calls
590 within this function. */
591 StaticTimer_t xTimerBuffer;
592
593         /* Create the software time.  xTimerCreateStatic() has an extra parameter
594         than the normal xTimerCreate() API function.  The parameter is a pointer to
595         the StaticTimer_t structure that will hold the software timer structure.  If
596         the parameter is passed as NULL then the structure will be allocated
597         dynamically, just as if xTimerCreate() had been called. */
598         xTimer = xTimerCreateStatic( "T1",                                      /* Text name for the task.  Helps debugging only.  Not used by FreeRTOS. */
599                                                                  xTimerPeriod,                  /* The period of the timer in ticks. */
600                                                                  pdTRUE,                                /* This is an auto-reload timer. */
601                                                                  ( void * ) &uxVariableToIncrement,     /* The variable incremented by the test is passed into the timer callback using the timer ID. */
602                                                                  prvTimerCallback,              /* The function to execute when the timer expires. */
603                                                                  &xTimerBuffer );               /* The buffer that will hold the software timer structure. */
604
605         /* The timer handle should equal the static timer structure passed into the
606         xTimerCreateStatic() function. */
607         configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer );
608
609         /* Set the variable to 0, wait for a few timer periods to expire, then check
610         the timer callback has incremented the variable to the expected value. */
611         uxVariableToIncrement = 0;
612
613         /* This is a low priority so a block time should not be needed. */
614         xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
615
616         if( xReturned != pdPASS )
617         {
618                 xErrorOccurred = pdTRUE;
619         }
620
621         vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
622
623         /* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS
624         times, and then stopped itself. */
625         if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
626         {
627                 xErrorOccurred = pdTRUE;
628         }
629
630         /* Finished with the timer, delete it. */
631         xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
632
633         /* Again, as this is a low priority task it is expected that the timer
634         command will have been sent even without a block time being used. */
635         if( xReturned != pdPASS )
636         {
637                 xErrorOccurred = pdTRUE;
638         }
639
640         /* Just to show the check task that this task is still executing. */
641         uxCycleCounter++;
642
643         /* Now do the same using a dynamically allocated software timer to ensure
644         the delete function is working correctly in both the static and dynamic
645         allocation cases. */
646         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
647         {
648                 xTimer = xTimerCreate( "T1",                                                            /* Text name for the task.  Helps debugging only.  Not used by FreeRTOS. */
649                                                             xTimerPeriod,                                               /* The period of the timer in ticks. */
650                                                                 pdTRUE,                                                         /* This is an auto-reload timer. */
651                                                                 ( void * ) &uxVariableToIncrement,      /* The variable incremented by the test is passed into the timer callback using the timer ID. */
652                                                                 prvTimerCallback );                                     /* The function to execute when the timer expires. */
653
654                 configASSERT( xTimer != NULL );
655
656                 uxVariableToIncrement = 0;
657                 xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
658
659                 if( xReturned != pdPASS )
660                 {
661                         xErrorOccurred = pdTRUE;
662                 }
663
664                 vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
665
666                 if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
667                 {
668                         xErrorOccurred = pdTRUE;
669                 }
670
671                 xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
672
673                 if( xReturned != pdPASS )
674                 {
675                         xErrorOccurred = pdTRUE;
676                 }
677         }
678         #endif
679 }
680 /*-----------------------------------------------------------*/
681
682 static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void )
683 {
684 EventGroupHandle_t xEventGroup;
685
686 /* StaticEventGroup_t is a publicly accessible structure that has the same size
687 and alignment requirements as the real event group structure.  It is provided as
688 a mechanism for applications to know the size of the event group (which is
689 dependent on the architecture and configuration file settings) without breaking
690 the strict data hiding policy by exposing the real event group internals.  This
691 StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic()
692 function calls within this function. */
693 StaticEventGroup_t xEventGroupBuffer;
694
695         /* Create the event group.  xEventGroupCreateStatic() has an extra parameter
696         than the normal xEventGroupCreate() API function.  The parameter is a
697         pointer to the StaticEventGroup_t structure that will hold the event group
698         structure. */
699         xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
700
701         /* The event group handle should equal the static event group structure
702         passed into the xEventGroupCreateStatic() function. */
703         configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer );
704
705         /* Ensure the event group passes a few sanity checks as a valid event
706         group. */
707         prvSanityCheckCreatedEventGroup( xEventGroup );
708
709         /* Delete the event group again so the buffers can be reused. */
710         vEventGroupDelete( xEventGroup );
711
712         /* Now do the same using a dynamically allocated event group to ensure the
713         delete function is working correctly in both the static and dynamic
714         allocation cases. */
715         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
716         {
717                 xEventGroup = xEventGroupCreate();
718                 configASSERT( xEventGroup != NULL );
719                 prvSanityCheckCreatedEventGroup( xEventGroup );
720                 vEventGroupDelete( xEventGroup );
721         }
722         #endif
723 }
724 /*-----------------------------------------------------------*/
725
726 static void prvCreateAndDeleteStaticallyAllocatedTasks( void )
727 {
728 TaskHandle_t xCreatedTask;
729
730 /* The variable that will hold the TCB of tasks created by this function.  See
731 the comments above the declaration of the xCreatorTaskTCBBuffer variable for
732 more information.  NOTE:  This is not static so relies on the tasks that use it
733 being deleted before this function returns and deallocates its stack.  That will
734 only be the case if configUSE_PREEMPTION is set to 1. */
735 StaticTask_t xTCBBuffer;
736
737 /* This buffer that will be used as the stack of tasks created by this function.
738 See the comments above the declaration of the uxCreatorTaskStackBuffer[] array
739 above for more information. */
740 static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
741
742         /* Create the task.  xTaskCreateStatic() has two more parameters than
743         the usual xTaskCreate() function.  The first new parameter is a pointer to
744         the pre-allocated stack.  The second new parameter is a pointer to the
745         StaticTask_t structure that will hold the task's TCB.  If both pointers are
746         passed as NULL then the respective object will be allocated dynamically as
747         if xTaskCreate() had been called. */
748         xCreatedTask = xTaskCreateStatic(
749                                                 prvStaticallyAllocatedTask,     /* Function that implements the task. */
750                                                 "Static",                                               /* Human readable name for the task. */
751                                                 configMINIMAL_STACK_SIZE,               /* Task's stack size, in words (not bytes!). */
752                                                 NULL,                                                   /* Parameter to pass into the task. */
753                                                 uxTaskPriorityGet( NULL ) + 1,  /* The priority of the task. */
754                                                 &( uxStackBuffer[ 0 ] ),                /* The buffer to use as the task's stack. */
755                                                 &xTCBBuffer );                                  /* The variable that will hold that task's TCB. */
756
757         /* Check the task was created correctly, then delete the task. */
758         if( xCreatedTask == NULL )
759         {
760                 xErrorOccurred = pdTRUE;
761         }
762         else if( eTaskGetState( xCreatedTask ) != eSuspended )
763         {
764                 /* The created task had a higher priority so should have executed and
765                 suspended itself by now. */
766                 xErrorOccurred = pdTRUE;
767         }
768         else
769         {
770                 vTaskDelete( xCreatedTask );
771         }
772
773         /* Now do the same using a dynamically allocated task to ensure the delete
774         function is working correctly in both the static and dynamic allocation
775         cases. */
776         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
777         {
778         BaseType_t xReturned;
779
780                 xReturned = xTaskCreate(
781                                                                         prvStaticallyAllocatedTask,             /* Function that implements the task - the same function is used but is actually dynamically allocated this time. */
782                                                                         "Static",                                               /* Human readable name for the task. */
783                                                                         configMINIMAL_STACK_SIZE,               /* Task's stack size, in words (not bytes!). */
784                                                                         NULL,                                                   /* Parameter to pass into the task. */
785                                                                         uxTaskPriorityGet( NULL ) + 1,  /* The priority of the task. */
786                                                                         &xCreatedTask );                                /* Handle of the task being created. */
787
788                 if( eTaskGetState( xCreatedTask ) != eSuspended )
789                 {
790                         xErrorOccurred = pdTRUE;
791                 }
792
793                 configASSERT( xReturned == pdPASS );
794                 if( xReturned != pdPASS )
795                 {
796                         xErrorOccurred = pdTRUE;
797                 }
798                 vTaskDelete( xCreatedTask );
799         }
800         #endif
801 }
802 /*-----------------------------------------------------------*/
803
804 static void prvStaticallyAllocatedTask( void *pvParameters )
805 {
806         ( void ) pvParameters;
807
808         /* The created task just suspends itself to wait to get deleted.  The task
809         that creates this task checks this task is in the expected Suspended state
810         before deleting it. */
811         vTaskSuspend( NULL );
812 }
813 /*-----------------------------------------------------------*/
814
815 static UBaseType_t prvRand( void )
816 {
817 const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
818
819         /* Utility function to generate a pseudo random number. */
820         ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
821         return( ( ulNextRand >> 16UL ) & 0x7fffUL );
822 }
823 /*-----------------------------------------------------------*/
824
825 static TickType_t prvGetNextDelayTime( void )
826 {
827 TickType_t xNextDelay;
828 const TickType_t xMaxDelay = pdMS_TO_TICKS( ( TickType_t ) 150 );
829 const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 );
830 const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 );
831
832         /* Generate the next delay time.  This is kept within a narrow band so as
833         not to disturb the timing of other tests - but does add in some pseudo
834         randomisation into the tests. */
835         do
836         {
837                 xNextDelay = prvRand() % xMaxDelay;
838
839                 /* Just in case this loop is executed lots of times. */
840                 vTaskDelay( xTinyDelay );
841
842         } while ( xNextDelay < xMinDelay );
843
844         return xNextDelay;
845 }
846 /*-----------------------------------------------------------*/
847
848 static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup )
849 {
850 EventBits_t xEventBits;
851 const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55;
852
853         /* The event group should not have any bits set yet. */
854         xEventBits = xEventGroupGetBits( xEventGroup );
855
856         if( xEventBits != ( EventBits_t ) 0 )
857         {
858                 xErrorOccurred = pdTRUE;
859         }
860
861         /* Some some bits, then read them back to check they are as expected. */
862         xEventGroupSetBits( xEventGroup, xFirstTestBits );
863
864         xEventBits = xEventGroupGetBits( xEventGroup );
865
866         if( xEventBits != xFirstTestBits )
867         {
868                 xErrorOccurred = pdTRUE;
869         }
870
871         xEventGroupSetBits( xEventGroup, xSecondTestBits );
872
873         xEventBits = xEventGroupGetBits( xEventGroup );
874
875         if( xEventBits != ( xFirstTestBits | xSecondTestBits ) )
876         {
877                 xErrorOccurred = pdTRUE;
878         }
879
880         /* Finally try clearing some bits too and check that operation proceeds as
881         expected. */
882         xEventGroupClearBits( xEventGroup, xFirstTestBits );
883
884         xEventBits = xEventGroupGetBits( xEventGroup );
885
886         if( xEventBits != xSecondTestBits )
887         {
888                 xErrorOccurred = pdTRUE;
889         }
890 }
891 /*-----------------------------------------------------------*/
892
893 static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount )
894 {
895 BaseType_t xReturned;
896 UBaseType_t x;
897 const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );
898 TickType_t xTickCount;
899
900         /* The binary semaphore should start 'empty', so a call to xSemaphoreTake()
901         should fail. */
902         xTickCount = xTaskGetTickCount();
903         xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
904
905         if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
906         {
907                 /* Did not block on the semaphore as long as expected. */
908                 xErrorOccurred = pdTRUE;
909         }
910
911         if( xReturned != pdFAIL )
912         {
913                 xErrorOccurred = pdTRUE;
914         }
915
916         /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount
917         times. */
918         for( x = 0; x < uxMaxCount; x++ )
919         {
920                 xReturned = xSemaphoreGive( xSemaphore );
921
922                 if( xReturned == pdFAIL )
923                 {
924                         xErrorOccurred = pdTRUE;
925                 }
926         }
927
928         /* Giving the semaphore again should fail, as it is 'full'. */
929         xReturned = xSemaphoreGive( xSemaphore );
930
931         if( xReturned != pdFAIL )
932         {
933                 xErrorOccurred = pdTRUE;
934         }
935
936         configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );
937
938         /* Should now be possible to 'take' the semaphore up to a maximum of
939         uxMaxCount times without blocking. */
940         for( x = 0; x < uxMaxCount; x++ )
941         {
942                 xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
943
944                 if( xReturned == pdFAIL )
945                 {
946                         xErrorOccurred = pdTRUE;
947                 }
948         }
949
950         /* Back to the starting condition, where the semaphore should not be
951         available. */
952         xTickCount = xTaskGetTickCount();
953         xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
954
955         if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
956         {
957                 /* Did not block on the semaphore as long as expected. */
958                 xErrorOccurred = pdTRUE;
959         }
960
961         if( xReturned != pdFAIL )
962         {
963                 xErrorOccurred = pdTRUE;
964         }
965
966         configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
967 }
968 /*-----------------------------------------------------------*/
969
970 static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue )
971 {
972 uint64_t ull, ullRead;
973 BaseType_t xReturned, xLoop;
974
975         /* This test is done twice to ensure the queue storage area wraps. */
976         for( xLoop = 0; xLoop < 2; xLoop++ )
977         {
978                 /* A very basic test that the queue can be written to and read from as
979                 expected.  First the queue should be empty. */
980                 xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
981                 if( xReturned != errQUEUE_EMPTY )
982                 {
983                         xErrorOccurred = pdTRUE;
984                 }
985
986                 /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS
987                 times. */
988                 for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
989                 {
990                         xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
991                         if( xReturned != pdPASS )
992                         {
993                                 xErrorOccurred = pdTRUE;
994                         }
995                 }
996
997                 /* Should not now be possible to write to the queue again. */
998                 xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
999                 if( xReturned != errQUEUE_FULL )
1000                 {
1001                         xErrorOccurred = pdTRUE;
1002                 }
1003
1004                 /* Now read back from the queue to ensure the data read back matches that
1005                 written. */
1006                 for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
1007                 {
1008                         xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );
1009
1010                         if( xReturned != pdPASS )
1011                         {
1012                                 xErrorOccurred = pdTRUE;
1013                         }
1014
1015                         if( ullRead != ull )
1016                         {
1017                                 xErrorOccurred = pdTRUE;
1018                         }
1019                 }
1020
1021                 /* The queue should be empty again. */
1022                 xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
1023                 if( xReturned != errQUEUE_EMPTY )
1024                 {
1025                         xErrorOccurred = pdTRUE;
1026                 }
1027         }
1028 }
1029 /*-----------------------------------------------------------*/
1030
1031 static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore )
1032 {
1033 const BaseType_t xLoops = 5;
1034 BaseType_t x, xReturned;
1035
1036         /* A very basic test that the recursive semaphore behaved like a recursive
1037         semaphore. First the semaphore should not be able to be given, as it has not
1038         yet been taken. */
1039         xReturned = xSemaphoreGiveRecursive( xSemaphore );
1040
1041         if( xReturned != pdFAIL )
1042         {
1043                 xErrorOccurred = pdTRUE;
1044         }
1045
1046         /* Now it should be possible to take the mutex a number of times. */
1047         for( x = 0; x < xLoops; x++ )
1048         {
1049                 xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK );
1050
1051                 if( xReturned != pdPASS )
1052                 {
1053                         xErrorOccurred = pdTRUE;
1054                 }
1055         }
1056
1057         /* Should be possible to give the semaphore the same number of times as it
1058         was given in the loop above. */
1059         for( x = 0; x < xLoops; x++ )
1060         {
1061                 xReturned = xSemaphoreGiveRecursive( xSemaphore );
1062
1063                 if( xReturned != pdPASS )
1064                 {
1065                         xErrorOccurred = pdTRUE;
1066                 }
1067         }
1068
1069         /* No more gives should be possible though. */
1070         xReturned = xSemaphoreGiveRecursive( xSemaphore );
1071
1072         if( xReturned != pdFAIL )
1073         {
1074                 xErrorOccurred = pdTRUE;
1075         }
1076 }
1077 /*-----------------------------------------------------------*/
1078
1079 BaseType_t xAreStaticAllocationTasksStillRunning( void )
1080 {
1081 static UBaseType_t uxLastCycleCounter = 0;
1082 BaseType_t xReturn;
1083
1084         if( uxCycleCounter == uxLastCycleCounter )
1085         {
1086                 xErrorOccurred = pdTRUE;
1087         }
1088         else
1089         {
1090                 uxLastCycleCounter = uxCycleCounter;
1091         }
1092
1093         if( xErrorOccurred != pdFALSE )
1094         {
1095                 xReturn = pdFAIL;
1096         }
1097         else
1098         {
1099                 xReturn = pdPASS;
1100         }
1101
1102         return xReturn;
1103 }
1104 /*-----------------------------------------------------------*/
1105
1106 /* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
1107 #endif /* configSUPPORT_STATIC_ALLOCATION == 1 */