]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Posix_GCC/src/main_full.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS / Demo / Posix_GCC / src / main_full.c
1 /*
2  * FreeRTOS Kernel V10.3.0
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  * NOTE 1: The Win32 port is a simulation (or is that emulation?) only!  Do not
31  * expect to get real time behaviour from the Win32 port or this demo
32  * application.  It is provided as a convenient development and demonstration
33  * test bed only.
34  *
35  * Windows will not be running the FreeRTOS simulator threads continuously, so
36  * the timing information in the FreeRTOS+Trace logs have no meaningful units.
37  * See the documentation page for the Windows simulator for an explanation of
38  * the slow timing:
39  * http://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html
40  * - READ THE WEB DOCUMENTATION FOR THIS PORT FOR MORE INFORMATION ON USING IT -
41  *
42  * NOTE 2:  This project provides two demo applications.  A simple blinky style
43  * project, and a more comprehensive test and demo application.  The
44  * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select
45  * between the two.  See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY
46  * in main.c.  This file implements the comprehensive test and demo version.
47  *
48  * NOTE 3:  This file only contains the source code that is specific to the
49  * full demo.  Generic functions, such FreeRTOS hook functions, are defined in
50  * main.c.
51  *******************************************************************************
52  *
53  * main() creates all the demo application tasks, then starts the scheduler.
54  * The web documentation provides more details of the standard demo application
55  * tasks, which provide no particular functionality but do provide a good
56  * example of how to use the FreeRTOS API.
57  *
58  * In addition to the standard demo tasks, the following tasks and tests are
59  * defined and/or created within this file:
60  *
61  * "Check" task - This only executes every five seconds but has a high priority
62  * to ensure it gets processor time.  Its main function is to check that all the
63  * standard demo tasks are still operational.  While no errors have been
64  * discovered the check task will print out "OK" and the current simulated tick
65  * time.  If an error is discovered in the execution of a task then the check
66  * task will print out an appropriate error message.
67  *
68  */
69
70
71 /* Standard includes. */
72 #include <stdlib.h>
73 #include <string.h>
74 #include <time.h>
75
76 /* Kernel includes. */
77 #include <FreeRTOS.h>
78 #include <task.h>
79 #include <queue.h>
80 #include <timers.h>
81 #include <semphr.h>
82
83 /* Standard demo includes. */
84 #include "BlockQ.h"
85 #include "integer.h"
86 #include "semtest.h"
87 #include "PollQ.h"
88 #include "GenQTest.h"
89 #include "QPeek.h"
90 #include "recmutex.h"
91 #include "flop.h"
92 #include "TimerDemo.h"
93 #include "countsem.h"
94 #include "death.h"
95 #include "dynamic.h"
96 #include "QueueSet.h"
97 #include "QueueOverwrite.h"
98 #include "EventGroupsDemo.h"
99 #include "IntSemTest.h"
100 #include "TaskNotify.h"
101 #include "QueueSetPolling.h"
102 #include "StaticAllocation.h"
103 #include "blocktim.h"
104 #include "AbortDelay.h"
105 #include "MessageBufferDemo.h"
106 #include "StreamBufferDemo.h"
107 #include "StreamBufferInterrupt.h"
108 #include "MessageBufferAMP.h"
109
110 /* Priorities at which the tasks are created. */
111 #define mainCHECK_TASK_PRIORITY                 ( configMAX_PRIORITIES - 2 )
112 #define mainQUEUE_POLL_PRIORITY                 ( tskIDLE_PRIORITY + 1 )
113 #define mainSEM_TEST_PRIORITY                   ( tskIDLE_PRIORITY + 1 )
114 #define mainBLOCK_Q_PRIORITY                    ( tskIDLE_PRIORITY + 2 )
115 #define mainCREATOR_TASK_PRIORITY               ( tskIDLE_PRIORITY + 3 )
116 #define mainFLASH_TASK_PRIORITY                 ( tskIDLE_PRIORITY + 1 )
117 #define mainINTEGER_TASK_PRIORITY               ( tskIDLE_PRIORITY )
118 #define mainGEN_QUEUE_TASK_PRIORITY             ( tskIDLE_PRIORITY )
119 #define mainFLOP_TASK_PRIORITY                  ( tskIDLE_PRIORITY )
120 #define mainQUEUE_OVERWRITE_PRIORITY    ( tskIDLE_PRIORITY )
121
122 #define mainTIMER_TEST_PERIOD                   ( 50 )
123
124 /*
125  * Exercises code that is not otherwise covered by the standard demo/test
126  * tasks.
127  */
128 extern BaseType_t xRunCodeCoverageTestAdditions( void );
129
130 /* Task function prototypes. */
131 static void prvCheckTask( void *pvParameters );
132
133 /* A task that is created from the idle task to test the functionality of
134 eTaskStateGet(). */
135 static void prvTestTask( void *pvParameters );
136
137 /*
138  * Called from the idle task hook function to demonstrate a few utility
139  * functions that are not demonstrated by any of the standard demo tasks.
140  */
141 static void prvDemonstrateTaskStateAndHandleGetFunctions( void );
142
143 /*
144  * Called from the idle task hook function to demonstrate the use of
145  * xTimerPendFunctionCall() as xTimerPendFunctionCall() is not demonstrated by
146  * any of the standard demo tasks.
147  */
148 static void prvDemonstratePendingFunctionCall( void );
149
150 /*
151  * The function that is pended by prvDemonstratePendingFunctionCall().
152  */
153 static void prvPendedFunction( void *pvParameter1, uint32_t ulParameter2 );
154
155 /*
156  * prvDemonstrateTimerQueryFunctions() is called from the idle task hook
157  * function to demonstrate the use of functions that query information about a
158  * software timer.  prvTestTimerCallback() is the callback function for the
159  * timer being queried.
160  */
161 static void prvDemonstrateTimerQueryFunctions( void );
162 static void prvTestTimerCallback( TimerHandle_t xTimer );
163
164 /*
165  * A task to demonstrate the use of the xQueueSpacesAvailable() function.
166  */
167 static void prvDemoQueueSpaceFunctions( void *pvParameters );
168
169 /*
170  * Tasks that ensure indefinite delays are truly indefinite.
171  */
172 static void prvPermanentlyBlockingSemaphoreTask( void *pvParameters );
173 static void prvPermanentlyBlockingNotificationTask( void *pvParameters );
174
175 /*
176  * The test function and callback function used when exercising the timer AP
177  * function that changes the timer's auto-reload mode.
178  */
179 static void prvDemonstrateChangingTimerReloadMode( void *pvParameters );
180 static void prvReloadModeTestTimerCallback( TimerHandle_t xTimer );
181
182 /*-----------------------------------------------------------*/
183
184 /* The variable into which error messages are latched. */
185 static char *pcStatusMessage = "No errors";
186
187 /* This semaphore is created purely to test using the vSemaphoreDelete() and
188 semaphore tracing API functions.  It has no other purpose. */
189 static SemaphoreHandle_t xMutexToDelete = NULL;
190
191 /*-----------------------------------------------------------*/
192
193 int main_full( void )
194 {
195         /* Start the check task as described at the top of this file. */
196         xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
197
198         /* Create the standard demo tasks. */
199         vStartTaskNotifyTask();
200         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
201         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
202         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
203         vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );
204         vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );
205         vStartQueuePeekTasks();
206         vStartMathTasks( mainFLOP_TASK_PRIORITY );
207         vStartRecursiveMutexTasks();
208         vStartCountingSemaphoreTasks();
209         vStartDynamicPriorityTasks();
210         vStartQueueSetTasks();
211         vStartQueueOverwriteTask( mainQUEUE_OVERWRITE_PRIORITY );
212         xTaskCreate( prvDemoQueueSpaceFunctions, NULL, configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); /* Name is null for code coverage. */
213         vStartEventGroupTasks();
214         vStartInterruptSemaphoreTasks();
215         vStartQueueSetPollingTask();
216         vCreateBlockTimeTasks();
217         vCreateAbortDelayTasks();
218         xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
219         xTaskCreate( prvPermanentlyBlockingSemaphoreTask, "BlockSem", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
220         xTaskCreate( prvPermanentlyBlockingNotificationTask, "BlockNoti", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
221         xTaskCreate( prvDemonstrateChangingTimerReloadMode, "TimerMode", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
222
223         vStartMessageBufferTasks( configMINIMAL_STACK_SIZE );
224         /* vStartStreamBufferTasks(); */
225         /* vStartStreamBufferInterruptDemo(); */
226         vStartMessageBufferAMPTasks( configMINIMAL_STACK_SIZE );
227
228         #if( configSUPPORT_STATIC_ALLOCATION == 1 )
229         {
230                 vStartStaticallyAllocatedTasks();
231         }
232         #endif
233
234         #if( configUSE_PREEMPTION != 0  )
235         {
236                 /* Don't expect these tasks to pass when preemption is not used. */
237                 //vStartTimerDemoTask( mainTIMER_TEST_PERIOD );
238         }
239         #endif
240
241         /* The suicide tasks must be created last as they need to know how many
242         tasks were running prior to their creation.  This then allows them to
243         ascertain whether or not the correct/expected number of tasks are running at
244         any given time. */
245         vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );
246
247         /* Create the semaphore that will be deleted in the idle task hook.  This
248         is done purely to test the use of vSemaphoreDelete(). */
249         xMutexToDelete = xSemaphoreCreateMutex();
250
251         /* Start the scheduler itself. */
252         vTaskStartScheduler();
253
254         /* Should never get here unless there was not enough heap space to create
255         the idle and other system tasks. */
256         return 0;
257 }
258 /*-----------------------------------------------------------*/
259
260 static void prvCheckTask( void *pvParameters )
261 {
262 TickType_t xNextWakeTime;
263 const TickType_t xCycleFrequency = pdMS_TO_TICKS( 2500UL );
264
265         /* Just to remove compiler warning. */
266         ( void ) pvParameters;
267
268         /* Initialise xNextWakeTime - this only needs to be done once. */
269         xNextWakeTime = xTaskGetTickCount();
270
271         for( ;; )
272         {
273                 /* Place this task in the blocked state until it is time to run again. */
274                 vTaskDelayUntil( &xNextWakeTime, xCycleFrequency );
275
276                 /* Check the standard demo tasks are running without error. */
277                 /* #if( configUSE_PREEMPTION != 0 ) */
278                 /* { */
279                 /*      /\* These tasks are only created when preemption is used. *\/ */
280                 /*      if( xAreTimerDemoTasksStillRunning( xCycleFrequency ) != pdTRUE ) */
281                 /*      { */
282                 /*              pcStatusMessage = "Error: TimerDemo"; */
283                 /*      } */
284                 /* } */
285                 /* #endif */
286
287                 /* if( xAreStreamBufferTasksStillRunning() != pdTRUE ) */
288                 /* { */
289                 /*      pcStatusMessage = "Error:  StreamBuffer"; */
290                 /* } */
291                 /* else  */if( xAreMessageBufferTasksStillRunning() != pdTRUE )
292                 {
293                         pcStatusMessage = "Error:  MessageBuffer";
294                 }
295                 else if( xAreTaskNotificationTasksStillRunning() != pdTRUE )
296                 {
297                         pcStatusMessage = "Error:  Notification";
298                 }
299                 else if( xAreInterruptSemaphoreTasksStillRunning() != pdTRUE )
300                 {
301                         pcStatusMessage = "Error: IntSem";
302                 }
303                 else if( xAreEventGroupTasksStillRunning() != pdTRUE )
304                 {
305                         pcStatusMessage = "Error: EventGroup";
306                 }
307                 else if( xAreIntegerMathsTaskStillRunning() != pdTRUE )
308                 {
309                         pcStatusMessage = "Error: IntMath";
310                 }
311                 else if( xAreGenericQueueTasksStillRunning() != pdTRUE )
312                 {
313                         pcStatusMessage = "Error: GenQueue";
314                 }
315                 else if( xAreQueuePeekTasksStillRunning() != pdTRUE )
316                 {
317                         pcStatusMessage = "Error: QueuePeek";
318                 }
319                 else if( xAreBlockingQueuesStillRunning() != pdTRUE )
320                 {
321                         pcStatusMessage = "Error: BlockQueue";
322                 }
323                 else if( xAreSemaphoreTasksStillRunning() != pdTRUE )
324                 {
325                         pcStatusMessage = "Error: SemTest";
326                 }
327                 else if( xArePollingQueuesStillRunning() != pdTRUE )
328                 {
329                         pcStatusMessage = "Error: PollQueue";
330                 }
331                 else if( xAreMathsTaskStillRunning() != pdPASS )
332                 {
333                         pcStatusMessage = "Error: Flop";
334                 }
335                 else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
336                 {
337                         pcStatusMessage = "Error: RecMutex";
338                 }
339                 else if( xAreCountingSemaphoreTasksStillRunning() != pdTRUE )
340                 {
341                         pcStatusMessage = "Error: CountSem";
342                 }
343                 else if( xIsCreateTaskStillRunning() != pdTRUE )
344                 {
345                         pcStatusMessage = "Error: Death";
346                 }
347                 else if( xAreDynamicPriorityTasksStillRunning() != pdPASS )
348                 {
349                         pcStatusMessage = "Error: Dynamic";
350                 }
351                 else if( xAreQueueSetTasksStillRunning() != pdPASS )
352                 {
353                         pcStatusMessage = "Error: Queue set";
354                 }
355                 else if( xIsQueueOverwriteTaskStillRunning() != pdPASS )
356                 {
357                         pcStatusMessage = "Error: Queue overwrite";
358                 }
359                 else if( xAreQueueSetPollTasksStillRunning() != pdPASS )
360                 {
361                         pcStatusMessage = "Error: Queue set polling";
362                 }
363                 else if( xAreBlockTimeTestTasksStillRunning() != pdPASS )
364                 {
365                         pcStatusMessage = "Error: Block time";
366                 }
367                 else if( xAreAbortDelayTestTasksStillRunning() != pdPASS )
368                 {
369                         pcStatusMessage = "Error: Abort delay";
370                 }
371                 /* else if( xIsInterruptStreamBufferDemoStillRunning() != pdPASS ) */
372                 /* { */
373                 /*      pcStatusMessage = "Error: Stream buffer interrupt"; */
374                 /* } */
375                 else if( xAreMessageBufferAMPTasksStillRunning() != pdPASS )
376                 {
377                         pcStatusMessage = "Error: Message buffer AMP";
378                 }
379
380                 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
381                         else if( xAreStaticAllocationTasksStillRunning() != pdPASS )
382                         {
383                                 pcStatusMessage = "Error: Static allocation";
384                         }
385                 #endif /* configSUPPORT_STATIC_ALLOCATION */
386         }
387 }
388 /*-----------------------------------------------------------*/
389
390 static void prvTestTask( void *pvParameters )
391 {
392 const unsigned long ulMSToSleep = 5;
393
394         /* Just to remove compiler warnings. */
395         ( void ) pvParameters;
396
397         /* This task is just used to test the eTaskStateGet() function.  It
398         does not have anything to do. */
399         for( ;; )
400         {
401                 /* Sleep to reduce CPU load, but don't sleep indefinitely in case there are
402                 tasks waiting to be terminated by the idle task. */
403         struct timespec ts;
404                 ts.tv_sec = ulMSToSleep / 1000;
405                 ts.tv_nsec = ulMSToSleep % 1000l * 1000000l;
406                 nanosleep( &ts, NULL );
407         }
408 }
409 /*-----------------------------------------------------------*/
410
411 /* Called from vApplicationIdleHook(), which is defined in main.c. */
412 void vFullDemoIdleFunction( void )
413 {
414 const unsigned long ulMSToSleep = 15;
415 void *pvAllocated;
416
417         /* Sleep to reduce CPU load, but don't sleep indefinitely in case there are
418         tasks waiting to be terminated by the idle task. */
419         struct timespec ts;
420         ts.tv_sec = ulMSToSleep / 1000;
421         ts.tv_nsec = ulMSToSleep % 1000l * 1000000l;
422         nanosleep( &ts, NULL );
423
424         /* Demonstrate a few utility functions that are not demonstrated by any of
425         the standard demo tasks. */
426         prvDemonstrateTaskStateAndHandleGetFunctions();
427
428         /* Demonstrate the use of xTimerPendFunctionCall(), which is not
429         demonstrated by any of the standard demo tasks. */
430         prvDemonstratePendingFunctionCall();
431
432         /* Demonstrate the use of functions that query information about a software
433         timer. */
434         prvDemonstrateTimerQueryFunctions();
435
436         /* If xMutexToDelete has not already been deleted, then delete it now.
437         This is done purely to demonstrate the use of, and test, the
438         vSemaphoreDelete() macro.  Care must be taken not to delete a semaphore
439         that has tasks blocked on it. */
440         if( xMutexToDelete != NULL )
441         {
442                 /* For test purposes, add the mutex to the registry, then remove it
443                 again, before it is deleted - checking its name is as expected before
444                 and after the assertion into the registry and its removal from the
445                 registry. */
446                 configASSERT( pcQueueGetName( xMutexToDelete ) == NULL );
447                 vQueueAddToRegistry( xMutexToDelete, "Test_Mutex" );
448                 configASSERT( strcmp( pcQueueGetName( xMutexToDelete ), "Test_Mutex" ) == 0 );
449                 vQueueUnregisterQueue( xMutexToDelete );
450                 configASSERT( pcQueueGetName( xMutexToDelete ) == NULL );
451
452                 vSemaphoreDelete( xMutexToDelete );
453                 xMutexToDelete = NULL;
454         }
455
456         /* Exercise heap_5 a bit.  The malloc failed hook will trap failed
457         allocations so there is no need to test here. */
458         pvAllocated = pvPortMalloc( ( rand() % 500 ) + 1 );
459         vPortFree( pvAllocated );
460
461         /* Exit after a fixed time so code coverage results are written to the
462         disk. */
463         #if( projCOVERAGE_TEST == 1 )
464         {
465                 const TickType_t xMaxRunTime = pdMS_TO_TICKS( 30000UL );
466
467                 /* Exercise code not otherwise executed by standard demo/test tasks. */
468                 if( xRunCodeCoverageTestAdditions() != pdPASS )
469                 {
470                         pcStatusMessage = "Code coverage additions failed.\r\n";
471                 }
472
473                 if( ( xTaskGetTickCount() - configINITIAL_TICK_COUNT ) >= xMaxRunTime )
474                 {
475                         vTaskEndScheduler();
476                 }
477         }
478         #endif
479 }
480 /*-----------------------------------------------------------*/
481
482 /* Called by vApplicationTickHook(), which is defined in main.c. */
483 void vFullDemoTickHookFunction( void )
484 {
485 TaskHandle_t xTimerTask;
486
487         /* Call the periodic timer test, which tests the timer API functions that
488         can be called from an ISR. */
489         /* #if( configUSE_PREEMPTION != 0 ) */
490         /* { */
491         /*      /\* Only created when preemption is used. *\/ */
492         /*      vTimerPeriodicISRTests(); */
493         /* } */
494         /* #endif */
495
496         /* Call the periodic queue overwrite from ISR demo. */
497         vQueueOverwritePeriodicISRDemo();
498
499         /* Write to a queue that is in use as part of the queue set demo to
500         demonstrate using queue sets from an ISR. */
501         vQueueSetAccessQueueSetFromISR();
502         vQueueSetPollingInterruptAccess();
503
504         /* Exercise event groups from interrupts. */
505         vPeriodicEventGroupsProcessing();
506
507         /* Exercise giving mutexes from an interrupt. */
508         vInterruptSemaphorePeriodicTest();
509
510         /* Exercise using task notifications from an interrupt. */
511         xNotifyTaskFromISR();
512
513         /* Writes to stream buffer byte by byte to test the stream buffer trigger
514         level functionality. */
515         /* vPeriodicStreamBufferProcessing(); */
516
517         /* Writes a string to a string buffer four bytes at a time to demonstrate
518         a stream being sent from an interrupt to a task. */
519         /* vBasicStreamBufferSendFromISR(); */
520
521         /* For code coverage purposes. */
522         xTimerTask = xTimerGetTimerDaemonTaskHandle();
523         configASSERT( uxTaskPriorityGetFromISR( xTimerTask ) == configTIMER_TASK_PRIORITY );
524         ( void ) xTimerTask; /* In case configASSERT() is not defined. */
525 }
526 /*-----------------------------------------------------------*/
527
528 static void prvPendedFunction( void *pvParameter1, uint32_t ulParameter2 )
529 {
530 static intptr_t ulLastParameter1 = 1000UL, ulLastParameter2 = 0UL;
531 intptr_t ulParameter1;
532
533         ulParameter1 = ( intptr_t ) pvParameter1;
534
535         /* Ensure the parameters are as expected. */
536         configASSERT( ulParameter1 == ( ulLastParameter1 + 1 ) );
537         configASSERT( ulParameter2 == ( ulLastParameter2 + 1 ) );
538
539         /* Remember the parameters for the next time the function is called. */
540         ulLastParameter1 = ulParameter1;
541         ulLastParameter2 = ulParameter2;
542
543         /* Remove compiler warnings in case configASSERT() is not defined. */
544         ( void ) ulLastParameter1;
545         ( void ) ulLastParameter2;
546 }
547 /*-----------------------------------------------------------*/
548
549 static void prvTestTimerCallback( TimerHandle_t xTimer )
550 {
551         /* This is the callback function for the timer accessed by
552         prvDemonstrateTimerQueryFunctions().  The callback does not do anything. */
553         ( void ) xTimer;
554 }
555 /*-----------------------------------------------------------*/
556
557 static void prvDemonstrateTimerQueryFunctions( void )
558 {
559 static TimerHandle_t xTimer = NULL;
560 const char *pcTimerName = "TestTimer";
561 volatile TickType_t xExpiryTime;
562 const TickType_t xDontBlock = 0;
563
564         if( xTimer == NULL )
565         {
566                 xTimer = xTimerCreate( pcTimerName, portMAX_DELAY, pdTRUE, NULL, prvTestTimerCallback );
567
568                 if( xTimer != NULL )
569                 {
570                         /* Called from the idle task so a block time must not be
571                         specified. */
572                         xTimerStart( xTimer, xDontBlock );
573                 }
574         }
575
576         if( xTimer != NULL )
577         {
578                 /* Demonstrate querying a timer's name. */
579                 configASSERT( strcmp( pcTimerGetName( xTimer ), pcTimerName ) == 0 );
580
581                 /* Demonstrate querying a timer's period. */
582                 configASSERT( xTimerGetPeriod( xTimer ) == portMAX_DELAY );
583
584                 /* Demonstrate querying a timer's next expiry time, although nothing is
585                 done with the returned value.  Note if the expiry time is less than the
586                 maximum tick count then the expiry time has overflowed from the current
587                 time.  In this case the expiry time was set to portMAX_DELAY, so it is
588                 expected to be less than the current time until the current time has
589                 itself overflowed. */
590                 xExpiryTime = xTimerGetExpiryTime( xTimer );
591                 ( void ) xExpiryTime;
592         }
593 }
594 /*-----------------------------------------------------------*/
595
596 static void prvDemonstratePendingFunctionCall( void )
597 {
598 static intptr_t ulParameter1 = 1000UL, ulParameter2 = 0UL;
599 const TickType_t xDontBlock = 0; /* This is called from the idle task so must *not* attempt to block. */
600
601         /* prvPendedFunction() just expects the parameters to be incremented by one
602         each time it is called. */
603         ulParameter1++;
604         ulParameter2++;
605
606         /* Pend the function call, sending the parameters. */
607         xTimerPendFunctionCall( prvPendedFunction, ( void * ) ulParameter1, ulParameter2, xDontBlock );
608 }
609 /*-----------------------------------------------------------*/
610
611 static void prvDemonstrateTaskStateAndHandleGetFunctions( void )
612 {
613 TaskHandle_t xIdleTaskHandle, xTimerTaskHandle;
614 char *pcTaskName;
615 static portBASE_TYPE xPerformedOneShotTests = pdFALSE;
616 TaskHandle_t xTestTask;
617 TaskStatus_t xTaskInfo;
618 extern StackType_t uxTimerTaskStack[];
619 static uint32_t ulLastIdleExecutionTime = 0;
620 uint32_t ulIdleExecutionTime;
621
622         /* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and
623         xTaskGetIdleTaskHandle() functions.  Also try using the function that sets
624         the task number. */
625         xIdleTaskHandle = xTaskGetIdleTaskHandle();
626         xTimerTaskHandle = xTimerGetTimerDaemonTaskHandle();
627
628         /* This is the idle hook, so the current task handle should equal the
629         returned idle task handle. */
630         if( xTaskGetCurrentTaskHandle() != xIdleTaskHandle )
631         {
632                 pcStatusMessage = "Error:  Returned idle task handle was incorrect";
633         }
634
635         /* Check the same handle is obtained using the idle task's name.  First try
636         with the wrong name, then the right name. */
637         if( xTaskGetHandle( "Idle" ) == xIdleTaskHandle )
638         {
639                 pcStatusMessage = "Error:  Returned handle for name Idle was incorrect";
640         }
641
642         if( xTaskGetHandle( "IDLE" ) != xIdleTaskHandle )
643         {
644                 pcStatusMessage = "Error:  Returned handle for name Idle was incorrect";
645         }
646
647         /* Check the timer task handle was returned correctly. */
648         pcTaskName = pcTaskGetName( xTimerTaskHandle );
649         if( strcmp( pcTaskName, "Tmr Svc" ) != 0 )
650         {
651                 pcStatusMessage = "Error:  Returned timer task handle was incorrect";
652         }
653
654         if( xTaskGetHandle( "Tmr Svc" ) != xTimerTaskHandle )
655         {
656                 pcStatusMessage = "Error:  Returned handle for name Tmr Svc was incorrect";
657         }
658
659         /* This task is running, make sure it's state is returned as running. */
660         if( eTaskStateGet( xIdleTaskHandle ) != eRunning )
661         {
662                 pcStatusMessage = "Error:  Returned idle task state was incorrect";
663         }
664
665         /* If this task is running, then the timer task must be blocked. */
666         if( eTaskStateGet( xTimerTaskHandle ) != eBlocked )
667         {
668                 pcStatusMessage = "Error:  Returned timer task state was incorrect";
669         }
670
671         /* Also with the vTaskGetInfo() function. */
672         vTaskGetInfo( xTimerTaskHandle, /* The task being queried. */
673                                           &xTaskInfo,           /* The structure into which information on the task will be written. */
674                                           pdTRUE,                       /* Include the task's high watermark in the structure. */
675                                           eInvalid );           /* Include the task state in the structure. */
676
677         /* Check the information returned by vTaskGetInfo() is as expected. */
678         if( ( xTaskInfo.eCurrentState != eBlocked )                                              ||
679                 ( strcmp( xTaskInfo.pcTaskName, "Tmr Svc" ) != 0 )                       ||
680                 ( xTaskInfo.uxCurrentPriority != configTIMER_TASK_PRIORITY ) ||
681                 ( xTaskInfo.pxStackBase != uxTimerTaskStack )                            ||
682                 ( xTaskInfo.xHandle != xTimerTaskHandle ) )
683         {
684                 pcStatusMessage = "Error:  vTaskGetInfo() returned incorrect information about the timer task";
685         }
686
687         /* Other tests that should only be performed once follow.  The test task
688         is not created on each iteration because to do so would cause the death
689         task to report an error (too many tasks running). */
690         if( xPerformedOneShotTests == pdFALSE )
691         {
692                 /* Don't run this part of the test again. */
693                 xPerformedOneShotTests = pdTRUE;
694
695                 /* Create a test task to use to test other eTaskStateGet() return values. */
696                 if( xTaskCreate( prvTestTask, "Test", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTestTask ) == pdPASS )
697                 {
698                         /* If this task is running, the test task must be in the ready state. */
699                         if( eTaskStateGet( xTestTask ) != eReady )
700                         {
701                                 pcStatusMessage = "Error: Returned test task state was incorrect 1";
702                         }
703
704                         /* Now suspend the test task and check its state is reported correctly. */
705                         vTaskSuspend( xTestTask );
706                         if( eTaskStateGet( xTestTask ) != eSuspended )
707                         {
708                                 pcStatusMessage = "Error: Returned test task state was incorrect 2";
709                         }
710
711                         /* Now delete the task and check its state is reported correctly. */
712                         vTaskDelete( xTestTask );
713                         if( eTaskStateGet( xTestTask ) != eDeleted )
714                         {
715                                 pcStatusMessage = "Error: Returned test task state was incorrect 3";
716                         }
717                 }
718         }
719
720         ulIdleExecutionTime = ulTaskGetIdleRunTimeCounter();
721         if( ulIdleExecutionTime == ulLastIdleExecutionTime )
722         {
723                 pcStatusMessage = "Error: Total amount of Idle task execution time did not change";
724         }
725         ulLastIdleExecutionTime = ulIdleExecutionTime;
726 }
727 /*-----------------------------------------------------------*/
728
729 static void prvDemoQueueSpaceFunctions( void *pvParameters )
730 {
731 QueueHandle_t xQueue = NULL;
732 const unsigned portBASE_TYPE uxQueueLength = 10;
733 unsigned portBASE_TYPE uxReturn, x;
734
735         /* Remove compiler warnings. */
736         ( void ) pvParameters;
737
738         /* Create the queue that will be used.  Nothing is actually going to be
739         sent or received so the queue item size is set to 0. */
740         xQueue = xQueueCreate( uxQueueLength, 0 );
741         configASSERT( xQueue );
742
743         for( ;; )
744         {
745                 for( x = 0; x < uxQueueLength; x++ )
746                 {
747                         /* Ask how many messages are available... */
748                         uxReturn = uxQueueMessagesWaiting( xQueue );
749
750                         /* Check the number of messages being reported as being available
751                         is as expected, and force an assert if not. */
752                         if( uxReturn != x )
753                         {
754                                 /* xQueue cannot be NULL so this is deliberately causing an
755                                 assert to be triggered as there is an error. */
756                                 configASSERT( xQueue == NULL );
757                         }
758
759                         /* Ask how many spaces remain in the queue... */
760                         uxReturn = uxQueueSpacesAvailable( xQueue );
761
762                         /* Check the number of spaces being reported as being available
763                         is as expected, and force an assert if not. */
764                         if( uxReturn != ( uxQueueLength - x ) )
765                         {
766                                 /* xQueue cannot be NULL so this is deliberately causing an
767                                 assert to be triggered as there is an error. */
768                                 configASSERT( xQueue == NULL );
769                         }
770
771                         /* Fill one more space in the queue. */
772                         xQueueSendToBack( xQueue, NULL, 0 );
773                 }
774
775                 /* Perform the same check while the queue is full. */
776                 uxReturn = uxQueueMessagesWaiting( xQueue );
777                 if( uxReturn != uxQueueLength )
778                 {
779                         configASSERT( xQueue == NULL );
780                 }
781
782                 uxReturn = uxQueueSpacesAvailable( xQueue );
783
784                 if( uxReturn != 0 )
785                 {
786                         configASSERT( xQueue == NULL );
787                 }
788
789                 /* The queue is full, start again. */
790                 xQueueReset( xQueue );
791
792                 #if( configUSE_PREEMPTION == 0 )
793                         taskYIELD();
794                 #endif
795         }
796 }
797 /*-----------------------------------------------------------*/
798
799 static void prvPermanentlyBlockingSemaphoreTask( void *pvParameters )
800 {
801 SemaphoreHandle_t xSemaphore;
802
803         /* Prevent compiler warning about unused parameter in the case that
804         configASSERT() is not defined. */
805         ( void ) pvParameters;
806
807         /* This task should block on a semaphore, and never return. */
808         xSemaphore = xSemaphoreCreateBinary();
809         configASSERT( xSemaphore );
810
811         xSemaphoreTake( xSemaphore, portMAX_DELAY );
812
813         /* The above xSemaphoreTake() call should never return, force an assert if
814         it does. */
815         configASSERT( pvParameters != NULL );
816         vTaskDelete( NULL );
817 }
818 /*-----------------------------------------------------------*/
819
820 static void prvPermanentlyBlockingNotificationTask( void *pvParameters )
821 {
822         /* Prevent compiler warning about unused parameter in the case that
823         configASSERT() is not defined. */
824         ( void ) pvParameters;
825
826         /* This task should block on a task notification, and never return. */
827         ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
828
829         /* The above ulTaskNotifyTake() call should never return, force an assert
830         if it does. */
831         configASSERT( pvParameters != NULL );
832         vTaskDelete( NULL );
833 }
834 /*-----------------------------------------------------------*/
835
836 static void prvReloadModeTestTimerCallback( TimerHandle_t xTimer )
837 {
838 intptr_t ulTimerID;
839
840         /* Increment the timer's ID to show the callback has executed. */
841         ulTimerID = ( intptr_t ) pvTimerGetTimerID( xTimer );
842         ulTimerID++;
843         vTimerSetTimerID( xTimer, ( void * ) ulTimerID );
844 }
845 /*-----------------------------------------------------------*/
846
847 static void prvDemonstrateChangingTimerReloadMode( void *pvParameters )
848 {
849 TimerHandle_t xTimer;
850 const char * const pcTimerName = "TestTimer";
851 const TickType_t x100ms = pdMS_TO_TICKS( 100UL );
852
853         /* Avoid compiler warnings about unused parameter. */
854         ( void ) pvParameters;
855
856         xTimer = xTimerCreate(  pcTimerName,
857                                                         x100ms,
858                                                         pdFALSE, /* Created as a one-shot timer. */
859                                                         0,
860                                                         prvReloadModeTestTimerCallback );
861         configASSERT( xTimer );
862         configASSERT( xTimerIsTimerActive( xTimer ) == pdFALSE );
863         configASSERT( xTimerGetTimerDaemonTaskHandle() != NULL );
864         configASSERT( strcmp( pcTimerName, pcTimerGetName( xTimer ) ) == 0 );
865         configASSERT( xTimerGetPeriod( xTimer ) == x100ms );
866
867         /* Timer was created as a one-shot timer.  Its callback just increments the
868         timer's ID - so set the ID to 0, let the timer run for a number of timeout
869         periods, then check the timer has only executed once. */
870         vTimerSetTimerID( xTimer, ( void * ) 0 );
871         xTimerStart( xTimer, portMAX_DELAY );
872         vTaskDelay( 3UL * x100ms );
873         configASSERT( ( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) ) == 1UL );
874
875         /* Now change the timer to be an auto-reload timer and check it executes
876         the expected number of times. */
877         vTimerSetReloadMode( xTimer, pdTRUE );
878         vTimerSetTimerID( xTimer, ( void * ) 0 );
879         xTimerStart( xTimer, 0 );
880         vTaskDelay( ( 3UL * x100ms ) + ( x100ms / 2UL ) ); /* Three full periods. */
881         configASSERT( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) == 3UL );
882         configASSERT( xTimerStop( xTimer, 0 ) != pdFAIL );
883
884         /* Now change the timer back to be a one-shot timer and check it only
885         executes once. */
886         vTimerSetReloadMode( xTimer, pdFALSE );
887         vTimerSetTimerID( xTimer, ( void * ) 0 );
888         xTimerStart( xTimer, 0 );
889         vTaskDelay( 3UL * x100ms );
890         configASSERT( xTimerStop( xTimer, 0 ) != pdFAIL );
891         configASSERT( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) == 1UL );
892
893         /* Clean up at the end. */
894         xTimerDelete( xTimer, portMAX_DELAY );
895         vTaskDelete( NULL );
896 }