2 * FreeRTOS Kernel V10.2.1
\r
3 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 * Contains sundry tests to exercise code that is not touched by the standard
\r
30 * demo tasks (which are predominantly test tasks). Some tests are incldued
\r
31 * here because they can only be executed when configASSERT() is not defined.
\r
34 #include "FreeRTOS.h"
\r
37 #include "event_groups.h"
\r
39 #include "stream_buffer.h"
\r
40 #include "message_buffer.h"
\r
42 /*-----------------------------------------------------------*/
\r
45 * Try creating static objects with one of the mandatory parameters set to NULL.
\r
46 * This can't be done in the standard demos as asserts() will get hit.
\r
48 static BaseType_t prvStaticAllocationsWithNullBuffers( void );
\r
51 * Code coverage analysis is performed with tracing turned off, so this
\r
52 * function executes the trace specific utility functions that would not
\r
53 * otherwise be executed..
\r
55 static BaseType_t prvTraceUtils( void );
\r
58 * The queue peek standard demo does not cover the case where an attempt to peek
\r
59 * times out, so test that case.
\r
61 static BaseType_t prvPeekTimeout( void );
\r
64 * Calls various interrupt safe functions designed to query the state of a
\r
67 static BaseType_t prvQueueQueryFromISR( void );
\r
70 * Hits a few paths in tasks state and status query functions not otherwise hit
\r
71 * by standard demo and test files.
\r
73 static BaseType_t prvTaskQueryFunctions( void );
\r
76 * None of the standard demo tasks use the task tags - exercise them here.
\r
78 static BaseType_t prvTaskTags( void );
\r
81 * Exercises a few of the query functions that are not otherwise exercised in
\r
82 * the standard demo and test functions.
\r
84 static BaseType_t prvTimerQuery( void );
\r
86 /*-----------------------------------------------------------*/
\r
88 static BaseType_t prvStaticAllocationsWithNullBuffers( void )
\r
90 uint32_t ulReturned = 0;
\r
91 BaseType_t xReturn = pdPASS;
\r
92 UBaseType_t uxDummy = 10;
\r
94 /* Don't expect to create any of the objects as a NULL parameter is always
\r
95 passed in place of a required buffer. Hence if all passes then none of the
\r
96 |= will be against 0, and ulReturned will still be zero at the end of this
\r
98 ulReturned |= ( uint32_t ) xEventGroupCreateStatic( NULL );
\r
100 /* Try creating a task twice, once with puxStackBuffer NULL, and once with
\r
101 pxTaskBuffer NULL. */
\r
102 ulReturned |= ( uint32_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
\r
103 "Dummy", /* Task name. */
\r
104 configMINIMAL_STACK_SIZE,
\r
108 ( StaticTask_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
\r
110 ulReturned |= ( uint32_t ) xTaskCreateStatic( NULL, /* Task to run, not needed as the task is not created. */
\r
111 "Dummy", /* Task name. */
\r
112 configMINIMAL_STACK_SIZE,
\r
115 ( StackType_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
\r
118 ulReturned |= ( uint32_t ) xQueueCreateStatic( uxDummy,
\r
120 ( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
\r
123 /* Try creating a stream buffer twice, once with pucStreamBufferStorageArea
\r
124 set to NULL, and once with pxStaticStreamBuffer set to NULL. */
\r
125 ulReturned |= ( uint32_t ) xStreamBufferCreateStatic( uxDummy,
\r
128 ( StaticStreamBuffer_t * ) &xReturn ); /* Dummy value just to pass a non NULL value in - won't get used. */
\r
130 ulReturned |= ( uint32_t ) xStreamBufferCreateStatic( uxDummy,
\r
132 ( uint8_t * ) &xReturn, /* Dummy value just to pass a non NULL value in - won't get used. */
\r
135 /* Try to create a task with a stack that is too large to be allocated. */
\r
136 if( xTaskCreate( NULL, "TooLarge", configTOTAL_HEAP_SIZE, NULL, tskIDLE_PRIORITY, NULL ) != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY )
\r
141 if( ulReturned != 0 )
\r
143 /* Something returned a non-NULL value. */
\r
149 /*-----------------------------------------------------------*/
\r
151 static BaseType_t prvTraceUtils( void )
\r
153 EventGroupHandle_t xEventGroup;
\r
154 QueueHandle_t xQueue;
\r
155 BaseType_t xReturn = pdPASS;
\r
156 const UBaseType_t xNumber = ( UBaseType_t ) 100, xQueueLength = ( UBaseType_t ) 1;
\r
157 UBaseType_t uxValue;
\r
158 TaskHandle_t xTaskHandle;
\r
159 StreamBufferHandle_t xStreamBuffer;
\r
160 MessageBufferHandle_t xMessageBuffer;
\r
162 /* Exercise the event group trace utilities. */
\r
163 xEventGroup = xEventGroupCreate();
\r
165 if( xEventGroup != NULL )
\r
167 vEventGroupSetNumber( xEventGroup, xNumber );
\r
168 if( uxEventGroupGetNumber( NULL ) != 0 )
\r
172 if( uxEventGroupGetNumber( xEventGroup ) != xNumber )
\r
177 vEventGroupDelete( xEventGroup );
\r
184 /* Exercise the queue trace utilities. */
\r
185 xQueue = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( uxValue ) );
\r
186 if( xQueue != NULL )
\r
188 vQueueSetQueueNumber( xQueue, xNumber );
\r
189 if( uxQueueGetQueueNumber( xQueue ) != xNumber )
\r
193 if( ucQueueGetQueueType( xQueue ) != queueQUEUE_TYPE_BASE )
\r
198 vQueueDelete( xQueue );
\r
205 /* Exercise the task trace utilities. Value of 100 is arbitrary, just want
\r
206 to check the value that is set is also read back. */
\r
208 xTaskHandle = xTaskGetCurrentTaskHandle();
\r
209 vTaskSetTaskNumber( xTaskHandle, uxValue );
\r
210 if( uxTaskGetTaskNumber( xTaskHandle ) != uxValue )
\r
214 if( uxTaskGetTaskNumber( NULL ) != 0 )
\r
219 /* Timer trace util functions are exercised in prvTimerQuery(). */
\r
222 /* Exercise the stream buffer utilities. Try creating with a trigger level
\r
223 of 0, it should then get capped to 1. */
\r
224 xStreamBuffer = xStreamBufferCreate( sizeof( uint32_t ), 0 );
\r
225 if( xStreamBuffer != NULL )
\r
227 vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxValue );
\r
228 if( uxStreamBufferGetStreamBufferNumber( xStreamBuffer ) != uxValue )
\r
232 if( ucStreamBufferGetStreamBufferType( xStreamBuffer ) != 0 )
\r
234 /* "Is Message Buffer" flag should have been 0. */
\r
238 vStreamBufferDelete( xStreamBuffer );
\r
245 xMessageBuffer = xMessageBufferCreate( sizeof( uint32_t ) );
\r
246 if( xMessageBuffer != NULL )
\r
248 if( ucStreamBufferGetStreamBufferType( xMessageBuffer ) == 0 )
\r
250 /* "Is Message Buffer" flag should have been 1. */
\r
254 vMessageBufferDelete( xMessageBuffer );
\r
263 /*-----------------------------------------------------------*/
\r
265 static BaseType_t prvPeekTimeout( void )
\r
267 QueueHandle_t xHandle;
\r
268 const UBaseType_t xQueueLength = 1;
\r
269 BaseType_t xReturn = pdPASS;
\r
270 TickType_t xBlockTime = ( TickType_t ) 2;
\r
271 UBaseType_t uxReceived;
\r
273 /* Create the queue just to try peeking it while it is empty. */
\r
274 xHandle = xQueueCreate( xQueueLength, ( UBaseType_t ) sizeof( xQueueLength ) );
\r
276 if( xHandle != NULL )
\r
278 if( uxQueueMessagesWaiting( xHandle ) != 0 )
\r
283 /* Ensure peeking from the queue times out as the queue is empty. */
\r
284 if( xQueuePeek( xHandle, &uxReceived, xBlockTime ) != pdFALSE )
\r
289 vQueueDelete( xHandle );
\r
298 /*-----------------------------------------------------------*/
\r
300 static BaseType_t prvQueueQueryFromISR( void )
\r
302 BaseType_t xReturn = pdPASS, xValue = 1;
\r
303 const UBaseType_t xISRQueueLength = ( UBaseType_t ) 1;
\r
304 const char *pcISRQueueName = "ISRQueue";
\r
305 QueueHandle_t xISRQueue = NULL;
\r
307 xISRQueue = xQueueCreate( xISRQueueLength, ( UBaseType_t ) sizeof( BaseType_t ) );
\r
309 if( xISRQueue != NULL )
\r
311 vQueueAddToRegistry( xISRQueue, pcISRQueueName );
\r
312 if( strcmp( pcQueueGetName( xISRQueue ), pcISRQueueName ) )
\r
317 /* Expect the queue to be empty here. */
\r
318 if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 0 )
\r
323 if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdTRUE )
\r
328 if( xQueueIsQueueFullFromISR( xISRQueue ) != pdFALSE )
\r
333 /* Now fill the queue - it only has one space. */
\r
334 if( xQueueSendFromISR( xISRQueue, &xValue, NULL ) != pdPASS )
\r
339 /* Check it now reports as full. */
\r
340 if( uxQueueMessagesWaitingFromISR( xISRQueue ) != 1 )
\r
345 if( xQueueIsQueueEmptyFromISR( xISRQueue ) != pdFALSE )
\r
350 if( xQueueIsQueueFullFromISR( xISRQueue ) != pdTRUE )
\r
355 vQueueDelete( xISRQueue );
\r
364 /*-----------------------------------------------------------*/
\r
366 static BaseType_t prvTaskQueryFunctions( void )
\r
368 static TaskStatus_t xStatus, *pxStatusArray;
\r
369 TaskHandle_t xTimerTask, xIdleTask;
\r
370 BaseType_t xReturn = pdPASS;
\r
371 UBaseType_t uxNumberOfTasks, uxReturned, ux;
\r
372 uint32_t ulTotalRunTime1, ulTotalRunTime2;
\r
373 const uint32_t ulRunTimeTollerance = ( uint32_t ) 0xfff;
\r
375 /* Obtain task status with the stack high water mark and without the
\r
377 vTaskGetInfo( NULL, &xStatus, pdTRUE, eRunning );
\r
379 if( uxTaskGetStackHighWaterMark( NULL ) != xStatus.usStackHighWaterMark )
\r
384 if( uxTaskGetStackHighWaterMark2( NULL ) != ( configSTACK_DEPTH_TYPE ) xStatus.usStackHighWaterMark )
\r
389 /* Now obtain a task status without the high water mark but with the state,
\r
390 which in the case of the idle task should be Read. */
\r
391 xTimerTask = xTimerGetTimerDaemonTaskHandle();
\r
392 vTaskSuspend( xTimerTask ); /* Should never suspend Timer task normally!. */
\r
393 vTaskGetInfo( xTimerTask, &xStatus, pdFALSE, eInvalid );
\r
394 if( xStatus.eCurrentState != eSuspended )
\r
398 if( xStatus.uxBasePriority != uxTaskPriorityGetFromISR( xTimerTask ) )
\r
402 if( xStatus.uxBasePriority != ( configMAX_PRIORITIES - 1 ) )
\r
406 xTaskResumeFromISR( xTimerTask );
\r
407 vTaskGetInfo( xTimerTask, &xStatus, pdTRUE, eInvalid );
\r
408 if( ( xStatus.eCurrentState != eReady ) && ( xStatus.eCurrentState != eBlocked ) )
\r
412 if( uxTaskGetStackHighWaterMark( xTimerTask ) != xStatus.usStackHighWaterMark )
\r
416 if( uxTaskGetStackHighWaterMark2( xTimerTask ) != ( configSTACK_DEPTH_TYPE ) xStatus.usStackHighWaterMark )
\r
421 /* Attempting to abort a delay in the idle task should be guaranteed to
\r
422 fail as the idle task should never block. */
\r
423 xIdleTask = xTaskGetIdleTaskHandle();
\r
424 if( xTaskAbortDelay( xIdleTask ) != pdFAIL )
\r
429 /* Create an array of task status objects large enough to hold information
\r
430 on the number of tasks at this time - note this may change at any time if
\r
431 higher priority tasks are executing and creating tasks. */
\r
432 uxNumberOfTasks = uxTaskGetNumberOfTasks();
\r
433 pxStatusArray = ( TaskStatus_t * ) pvPortMalloc( uxNumberOfTasks * sizeof( TaskStatus_t ) );
\r
435 if( pxStatusArray != NULL )
\r
437 /* Pass part of the array into uxTaskGetSystemState() to ensure it doesn't
\r
438 try using more space than there is available. */
\r
439 uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks / ( UBaseType_t ) 2, NULL );
\r
440 if( uxReturned != ( UBaseType_t ) 0 )
\r
445 /* Now do the same but passing in the complete array size, this is done
\r
446 twice to check for a difference in the total run time. */
\r
447 uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime1 );
\r
448 memset( ( void * ) pxStatusArray, 0xaa, uxNumberOfTasks * sizeof( TaskStatus_t ) );
\r
449 uxReturned = uxTaskGetSystemState( pxStatusArray, uxNumberOfTasks, &ulTotalRunTime2 );
\r
450 if( ( ulTotalRunTime2 - ulTotalRunTime1 ) > ulRunTimeTollerance )
\r
455 /* Basic santity check of array contents. */
\r
456 for( ux = 0; ux < uxReturned; ux++ )
\r
458 if( pxStatusArray[ ux ].eCurrentState >= ( UBaseType_t ) eInvalid )
\r
462 if( pxStatusArray[ ux ].uxCurrentPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
\r
468 vPortFree( pxStatusArray );
\r
477 /*-----------------------------------------------------------*/
\r
479 static BaseType_t prvDummyTagFunction( void *pvParameter )
\r
481 return ( BaseType_t ) pvParameter;
\r
483 /*-----------------------------------------------------------*/
\r
485 static BaseType_t prvTaskTags( void )
\r
487 BaseType_t xReturn = pdPASS, xParameter = ( BaseType_t ) 0xDEADBEEF;
\r
488 TaskHandle_t xTask;
\r
490 /* First try with the handle of a different task. Use the timer task for
\r
492 xTask = xTimerGetTimerDaemonTaskHandle();
\r
494 vTaskSetApplicationTaskTag( xTask, prvDummyTagFunction );
\r
495 if( xTaskGetApplicationTaskTag( xTask ) != prvDummyTagFunction )
\r
501 if( xTaskCallApplicationTaskHook( xTask, ( void * ) xParameter ) != xParameter )
\r
505 if( xTaskCallApplicationTaskHook( xTask, ( void * ) NULL ) != pdFAIL )
\r
511 /* Try FromISR version too. */
\r
512 if( xTaskGetApplicationTaskTagFromISR( xTask ) != prvDummyTagFunction )
\r
517 /* Now try with a NULL handle, so using this task. */
\r
518 vTaskSetApplicationTaskTag( NULL, NULL );
\r
519 if( xTaskGetApplicationTaskTag( NULL ) != NULL )
\r
523 if( xTaskGetApplicationTaskTagFromISR( NULL ) != NULL )
\r
528 vTaskSetApplicationTaskTag( NULL, prvDummyTagFunction );
\r
529 if( xTaskGetApplicationTaskTag( NULL ) != prvDummyTagFunction )
\r
535 if( xTaskCallApplicationTaskHook( NULL, ( void * ) xParameter ) != xParameter )
\r
539 if( xTaskCallApplicationTaskHook( NULL, ( void * ) NULL ) != pdFAIL )
\r
545 /* Try FromISR version too. */
\r
546 if( xTaskGetApplicationTaskTagFromISR( NULL ) != prvDummyTagFunction )
\r
551 vTaskSetApplicationTaskTag( NULL, NULL );
\r
552 if( xTaskGetApplicationTaskTag( NULL ) != NULL )
\r
559 /*-----------------------------------------------------------*/
\r
561 static BaseType_t prvTimerQuery( void )
\r
563 TimerHandle_t xTimer;
\r
564 BaseType_t xReturn = pdPASS;
\r
565 const char *pcTimerName = "TestTimer";
\r
566 const TickType_t xTimerPeriod = ( TickType_t ) 100;
\r
567 const UBaseType_t uxTimerNumber = ( UBaseType_t ) 55;
\r
569 xTimer = xTimerCreate( pcTimerName,
\r
572 ( void * ) xTimerPeriod,
\r
573 NULL ); /* Not actually going to start timer so NULL callback is ok. */
\r
575 if( xTimer != NULL )
\r
577 if( xTimerGetPeriod( xTimer ) != xTimerPeriod )
\r
582 if( strcmp( pcTimerGetName( xTimer ), pcTimerName ) != 0 )
\r
587 vTimerSetTimerNumber( xTimer, uxTimerNumber );
\r
588 if( uxTimerGetTimerNumber( xTimer ) != uxTimerNumber )
\r
593 xTimerDelete( xTimer, portMAX_DELAY );
\r
602 /*-----------------------------------------------------------*/
\r
604 BaseType_t xRunCodeCoverageTestAdditions( void )
\r
606 BaseType_t xReturn = pdPASS;
\r
608 xReturn &= prvStaticAllocationsWithNullBuffers();
\r
609 xReturn &= prvTraceUtils();
\r
610 xReturn &= prvPeekTimeout();
\r
611 xReturn &= prvQueueQueryFromISR();
\r
612 xReturn &= prvTaskQueryFunctions();
\r
613 xReturn &= prvTaskTags();
\r
614 xReturn &= prvTimerQuery();
\r
618 /*-----------------------------------------------------------*/
\r