2 FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
28 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
29 >>! obliged to provide the source code for proprietary components !<<
\r
30 >>! outside of the FreeRTOS kernel. !<<
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
68 * Tests the behaviour of direct task notifications.
\r
71 /* Standard includes. */
\r
74 /* Scheduler include files. */
\r
75 #include "FreeRTOS.h"
\r
79 /* Demo program include files. */
\r
80 #include "TaskNotify.h"
\r
82 #define notifyTASK_PRIORITY ( tskIDLE_PRIORITY )
\r
84 /*-----------------------------------------------------------*/
\r
87 * Implementation of the task that gets notified.
\r
89 static void prvNotifiedTask( void *pvParameters );
\r
92 * Performs a few initial tests that can be done prior to creating the second
\r
95 static void prvSingleTaskTests( void );
\r
98 * Software timer callback function from which xTaskNotify() is called.
\r
100 static void prvNotifyingTimer( TimerHandle_t xTimer );
\r
103 * Utility function to create pseudo random numbers.
\r
105 static UBaseType_t prvRand( void );
\r
107 /*-----------------------------------------------------------*/
\r
109 /* Used to latch errors during the test's execution. */
\r
110 static BaseType_t xErrorStatus = pdPASS;
\r
112 /* Used to ensure the task has not stalled. */
\r
113 static volatile uint32_t ulNotifyCycleCount = 0;
\r
115 /* The handle of the task that receives the notifications. */
\r
116 static TaskHandle_t xTaskToNotify = NULL;
\r
118 /* Used to count the notifications sent to the task from a software timer and
\r
119 the number of notifications received by the task from the software timer. The
\r
120 two should stay synchronised. */
\r
121 static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
\r
123 /* The timer used to notify the task. */
\r
124 static TimerHandle_t xTimer = NULL;
\r
126 /* Used by the pseudo random number generating function. */
\r
127 static uint32_t ulNextRand = 0;
\r
129 /*-----------------------------------------------------------*/
\r
131 void vStartTaskNotifyTask( void )
\r
133 /* Create the task that performs some tests by itself, then loops around
\r
134 being notified by both a software timer and an interrupt. */
\r
135 xTaskCreate( prvNotifiedTask, "Notified", configMINIMAL_STACK_SIZE, NULL, notifyTASK_PRIORITY, &xTaskToNotify );
\r
137 /* Pseudo seed the random number generator. */
\r
138 ulNextRand = ( uint32_t ) prvRand;
\r
140 /*-----------------------------------------------------------*/
\r
142 static void prvSingleTaskTests( void )
\r
144 const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
\r
145 BaseType_t xReturned;
\r
146 uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue;
\r
147 TickType_t xTimeOnEntering;
\r
148 const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
\r
149 const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
\r
151 /* -------------------------------------------------------------------------
\r
152 Check blocking when there are no notifications. */
\r
153 xTimeOnEntering = xTaskGetTickCount();
\r
154 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
156 /* Should have blocked for the entire block time. */
\r
157 if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
\r
159 xErrorStatus = pdFAIL;
\r
161 configASSERT( xReturned == pdFAIL );
\r
162 configASSERT( ulNotifiedValue == 0UL );
\r
167 /* -------------------------------------------------------------------------
\r
168 Check no blocking when notifications are pending. First notify itself -
\r
169 this would not be a normal thing to do and is done here for test purposes
\r
171 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
\r
173 /* Even through the 'without overwrite' action was used the update should
\r
174 have been successful. */
\r
175 configASSERT( xReturned == pdPASS );
\r
177 /* The task should now have a notification pending, and so not time out. */
\r
178 xTimeOnEntering = xTaskGetTickCount();
\r
179 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
181 if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
\r
183 xErrorStatus = pdFAIL;
\r
186 /* The task should have been notified, and the notified value should
\r
187 be equal to ulFirstNotifiedConst. */
\r
188 configASSERT( xReturned == pdPASS );
\r
189 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
191 /* Incremented to show the task is still running. */
\r
192 ulNotifyCycleCount++;
\r
198 /*--------------------------------------------------------------------------
\r
199 Check the non-overwriting functionality. The notification is done twice
\r
200 using two different notification values. The action says don't overwrite so
\r
201 only the first notification should pass and the value read back should also
\r
202 be that used with the first notification. */
\r
203 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
\r
204 configASSERT( xReturned == pdPASS );
\r
206 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
\r
207 configASSERT( xReturned == pdFAIL );
\r
209 /* Waiting for the notification should now return immediately so a block
\r
210 time of zero is used. */
\r
211 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
213 configASSERT( xReturned == pdPASS );
\r
214 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
220 /*--------------------------------------------------------------------------
\r
221 Do the same again, only this time use the overwriting version. This time
\r
222 both notifications should pass, and the value written the second time should
\r
223 overwrite the value written the first time, and so be the value that is read
\r
225 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
\r
226 configASSERT( xReturned == pdPASS );
\r
227 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
\r
228 configASSERT( xReturned == pdPASS );
\r
229 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
230 configASSERT( xReturned == pdPASS );
\r
231 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
236 /*--------------------------------------------------------------------------
\r
237 Check notifications with no action pass without updating the value. Even
\r
238 though ulFirstNotifiedConst is used as the value the value read back should
\r
239 remain at ulSecondNotifiedConst. */
\r
240 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
\r
241 configASSERT( xReturned == pdPASS );
\r
242 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
243 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
248 /*--------------------------------------------------------------------------
\r
249 Check incrementing values. Send ulMaxLoop increment notifications, then
\r
250 ensure the received value is as expected - which should be
\r
251 ulSecondNotificationValueConst plus how ever many times to loop iterated. */
\r
252 for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
\r
254 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
\r
255 configASSERT( xReturned == pdPASS );
\r
258 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
259 configASSERT( xReturned == pdPASS );
\r
260 configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
\r
262 /* Should not be any notifications pending now. */
\r
263 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
264 configASSERT( xReturned == pdFAIL );
\r
269 /*--------------------------------------------------------------------------
\r
270 Check all bits can be set by notifying the task with one additional bit set
\r
271 on each notification, and exiting the loop when all the bits are found to be
\r
272 set. As there are 32-bits the loop should execute 32 times before all the
\r
273 bits are found to be set. */
\r
274 ulNotifyingValue = 0x01;
\r
277 /* Start with all bits clear. */
\r
278 xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
282 /* Set the next bit in the task's notified value. */
\r
283 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
\r
285 /* Wait for the notified value - which of course will already be
\r
286 available. Don't clear the bits on entry or exit as this loop is exited
\r
287 when all the bits are set. */
\r
288 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
289 configASSERT( xReturned == pdPASS );
\r
293 /* Use the next bit on the next iteration around this loop. */
\r
294 ulNotifyingValue <<= 1UL;
\r
296 } while ( ulNotifiedValue != ULONG_MAX );
\r
298 /* As a 32-bit value was used the loop should have executed 32 times before
\r
299 all the bits were set. */
\r
300 configASSERT( ulLoop == 32 );
\r
305 /*--------------------------------------------------------------------------
\r
306 Check bits are cleared on entry but not on exit when a notification fails
\r
307 to arrive before timing out - both with and without a timeout value. Wait
\r
308 for the notification again - but this time it is not given by anything and
\r
309 should return pdFAIL. The parameters are set to clear bit zero on entry and
\r
310 bit one on exit. As no notification was received only the bit cleared on
\r
311 entry should actually get cleared. */
\r
312 xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
\r
313 configASSERT( xReturned == pdFAIL );
\r
315 /* Notify the task with no action so as not to update the bits even though
\r
316 ULONG_MAX is used as the notification value. */
\r
317 xTaskNotify( xTaskToNotify, ULONG_MAX, eNoAction );
\r
319 /* Reading back the value should should find bit 0 is clear, as this was
\r
320 cleared on entry, but bit 1 is not clear as it will not have been cleared on
\r
321 exit as no notification was received. */
\r
322 xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
\r
323 configASSERT( xReturned == pdPASS );
\r
324 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) );
\r
330 /*--------------------------------------------------------------------------
\r
331 Now try clearing the bit on exit. For that to happen a notification must be
\r
332 received, so the task is notified first. */
\r
333 xTaskNotify( xTaskToNotify, 0, eNoAction );
\r
334 xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
\r
336 /* However as the bit is cleared on exit, after the returned notification
\r
337 value is set, the returned notification value should not have the bit
\r
339 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) );
\r
341 /* ...but reading the value back again should find that the bit was indeed
\r
342 cleared internally. The returned value should be pdFAIL however as nothing
\r
343 has notified the task in the mean time. */
\r
344 xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
\r
345 configASSERT( xReturned == pdFAIL );
\r
346 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
350 /* Incremented to show the task is still running. */
\r
351 ulNotifyCycleCount++;
\r
353 /* Leave all bits cleared. */
\r
354 xTaskNotifyWait( ULONG_MAX, 0, NULL, 0 );
\r
356 /*-----------------------------------------------------------*/
\r
358 static void prvNotifyingTimer( TimerHandle_t xNotUsed )
\r
362 xTaskNotifyGive( xTaskToNotify );
\r
364 /* This value is also incremented from an interrupt. */
\r
365 taskENTER_CRITICAL();
\r
367 ulTimerNotificationsSent++;
\r
369 taskEXIT_CRITICAL();
\r
371 /*-----------------------------------------------------------*/
\r
373 static void prvNotifiedTask( void *pvParameters )
\r
375 const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
\r
376 TickType_t xPeriod;
\r
378 /* Remove compiler warnings about unused parameters. */
\r
379 ( void ) pvParameters;
\r
381 /* Run a few tests that can be done from a single task before entering the
\r
383 prvSingleTaskTests();
\r
385 /* Create the software timer that is used to send notifications to this
\r
386 task. Notifications are also received from an interrupt. */
\r
387 xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
\r
391 /* Start the timer again with a different period. Sometimes the period
\r
392 will be higher than the tasks block time, sometimes it will be lower
\r
393 than the tasks block time. */
\r
394 xPeriod = prvRand() % xMaxPeriod;
\r
395 if( xPeriod < xMinPeriod )
\r
397 xPeriod = xMinPeriod;
\r
400 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
\r
401 xTimerStart( xTimer, portMAX_DELAY );
\r
403 /* Block waiting for the notification again with a different period.
\r
404 Sometimes the period will be higher than the tasks block time, sometimes
\r
405 it will be lower than the tasks block time. */
\r
406 xPeriod = prvRand() % xMaxPeriod;
\r
407 if( xPeriod < xMinPeriod )
\r
409 xPeriod = xMinPeriod;
\r
412 /* Block to wait for a notification but without clearing the
\r
413 notification count, so only add one to the count of received
\r
414 notifications as any other notifications will remain pending. */
\r
415 if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
\r
417 ulTimerNotificationsReceived++;
\r
421 /* Take a notification without clearing again, but this time without a
\r
422 block time specified. */
\r
423 if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
\r
425 ulTimerNotificationsReceived++;
\r
428 /* Wait for the next notification from the timer, clearing all
\r
429 notifications if one is received, so this time adding the total number
\r
430 of notifications that were pending as none will be left pending after
\r
431 the function call. */
\r
432 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
\r
434 /* Wait for the next notification again, clearing all notifications if
\r
435 one is received, but this time blocking indefinitely. */
\r
436 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
438 /* Incremented to show the task is still running. */
\r
439 ulNotifyCycleCount++;
\r
442 /*-----------------------------------------------------------*/
\r
444 void xNotifyTaskFromISR( void )
\r
446 static BaseType_t xCallCount = 0;
\r
447 const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
\r
449 /* The task performs some tests before starting the timer that gives the
\r
450 notification from this interrupt. If the timer has not been created yet
\r
451 then the initial tests have not yet completed and the notification should
\r
453 if( xTimer != NULL )
\r
457 if( xCallCount >= xCallInterval )
\r
459 /* It is time to 'give' the notification again. */
\r
462 xTaskNotifyGiveFromISR( xTaskToNotify, NULL );
\r
463 ulTimerNotificationsSent++;
\r
467 /*-----------------------------------------------------------*/
\r
469 /* This is called to check the created tasks are still running and have not
\r
470 detected any errors. */
\r
471 BaseType_t xAreTaskNotificationTasksStillRunning( void )
\r
473 static uint32_t ulLastNotifyCycleCount = 0;
\r
474 const uint32_t ulMaxSendReceiveDeviation = 5UL;
\r
476 /* Check the cycle count is still incrementing to ensure the task is still
\r
477 actually running. */
\r
478 if( ulLastNotifyCycleCount == ulNotifyCycleCount )
\r
480 xErrorStatus = pdFAIL;
\r
484 ulLastNotifyCycleCount = ulNotifyCycleCount;
\r
487 /* Check the count of 'takes' from the software timer is keeping track with
\r
488 the amount of 'gives'. */
\r
489 if( ulTimerNotificationsSent > ulTimerNotificationsSent )
\r
491 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
\r
493 xErrorStatus = pdFAIL;
\r
497 return xErrorStatus;
\r
499 /*-----------------------------------------------------------*/
\r
501 static UBaseType_t prvRand( void )
\r
503 const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
\r
505 /* Utility function to generate a pseudo random number. */
\r
506 ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
\r
507 return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
\r
509 /*-----------------------------------------------------------*/
\r