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 /*-----------------------------------------------------------*/
\r
128 void vStartTaskNotifyTask( void )
\r
130 /* Create the task that performs some tests by itself, then loops around
\r
131 being notified by both a software timer and an interrupt. */
\r
132 xTaskCreate( prvNotifiedTask, "Notified", configMINIMAL_STACK_SIZE, NULL, notifyTASK_PRIORITY, &xTaskToNotify );
\r
134 /*-----------------------------------------------------------*/
\r
136 static void prvSingleTaskTests( void )
\r
138 const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
\r
139 BaseType_t xReturned;
\r
140 uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue;
\r
141 TickType_t xTimeOnEntering;
\r
142 const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
\r
143 const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
\r
145 /* -------------------------------------------------------------------------
\r
146 Check blocking when there are no notifications. */
\r
147 xTimeOnEntering = xTaskGetTickCount();
\r
148 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
150 /* Should have blocked for the entire block time. */
\r
151 if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
\r
153 xErrorStatus = pdFAIL;
\r
155 configASSERT( xReturned == pdFAIL );
\r
156 configASSERT( ulNotifiedValue == 0UL );
\r
161 /* -------------------------------------------------------------------------
\r
162 Check no blocking when notifications are pending. First notify itself -
\r
163 this would not be a normal thing to do and is done here for test purposes
\r
165 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
\r
167 /* Even through the 'without overwrite' action was used the update should
\r
168 have been successful. */
\r
169 configASSERT( xReturned == pdPASS );
\r
171 /* The task should now have a notification pending, and so not time out. */
\r
172 xTimeOnEntering = xTaskGetTickCount();
\r
173 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
175 if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
\r
177 xErrorStatus = pdFAIL;
\r
180 /* The task should have been notified, and the notified value should
\r
181 be equal to ulFirstNotifiedConst. */
\r
182 configASSERT( xReturned == pdPASS );
\r
183 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
185 /* Incremented to show the task is still running. */
\r
186 ulNotifyCycleCount++;
\r
192 /*--------------------------------------------------------------------------
\r
193 Check the non-overwriting functionality. The notification is done twice
\r
194 using two different notification values. The action says don't overwrite so
\r
195 only the first notification should pass and the value read back should also
\r
196 be that used with the first notification. */
\r
197 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
\r
198 configASSERT( xReturned == pdPASS );
\r
200 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
\r
201 configASSERT( xReturned == pdFAIL );
\r
203 /* Waiting for the notification should now return immediately so a block
\r
204 time of zero is used. */
\r
205 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
207 configASSERT( xReturned == pdPASS );
\r
208 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
214 /*--------------------------------------------------------------------------
\r
215 Do the same again, only this time use the overwriting version. This time
\r
216 both notifications should pass, and the value written the second time should
\r
217 overwrite the value written the first time, and so be the value that is read
\r
219 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
\r
220 configASSERT( xReturned == pdPASS );
\r
221 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
\r
222 configASSERT( xReturned == pdPASS );
\r
223 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
224 configASSERT( xReturned == pdPASS );
\r
225 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
230 /*--------------------------------------------------------------------------
\r
231 Check notifications with no action pass without updating the value. Even
\r
232 though ulFirstNotifiedConst is used as the value the value read back should
\r
233 remain at ulSecondNotifiedConst. */
\r
234 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
\r
235 configASSERT( xReturned == pdPASS );
\r
236 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
237 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
242 /*--------------------------------------------------------------------------
\r
243 Check incrementing values. Send ulMaxLoop increment notifications, then
\r
244 ensure the received value is as expected - which should be
\r
245 ulSecondNotificationValueConst plus how ever many times to loop iterated. */
\r
246 for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
\r
248 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
\r
249 configASSERT( xReturned == pdPASS );
\r
252 xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
253 configASSERT( xReturned == pdPASS );
\r
254 configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
\r
256 /* Should not be any notifications pending now. */
\r
257 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
258 configASSERT( xReturned == pdFAIL );
\r
263 /*--------------------------------------------------------------------------
\r
264 Check all bits can be set by notifying the task with one additional bit set
\r
265 on each notification, and exiting the loop when all the bits are found to be
\r
266 set. As there are 32-bits the loop should execute 32 times before all the
\r
267 bits are found to be set. */
\r
268 ulNotifyingValue = 0x01;
\r
271 /* Start with all bits clear. */
\r
272 xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 );
\r
276 /* Set the next bit in the task's notified value. */
\r
277 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
\r
279 /* Wait for the notified value - which of course will already be
\r
280 available. Don't clear the bits on entry or exit as this loop is exited
\r
281 when all the bits are set. */
\r
282 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
283 configASSERT( xReturned == pdPASS );
\r
287 /* Use the next bit on the next iteration around this loop. */
\r
288 ulNotifyingValue <<= 1UL;
\r
290 } while ( ulNotifiedValue != ULONG_MAX );
\r
292 /* As a 32-bit value was used the loop should have executed 32 times before
\r
293 all the bits were set. */
\r
294 configASSERT( ulLoop == 32 );
\r
299 /*--------------------------------------------------------------------------
\r
300 Check bits are cleared on entry but not on exit when a notification fails
\r
301 to arrive before timing out - both with and without a timeout value. Wait
\r
302 for the notification again - but this time it is not given by anything and
\r
303 should return pdFAIL. The parameters are set to clear bit zero on entry and
\r
304 bit one on exit. As no notification was received only the bit cleared on
\r
305 entry should actually get cleared. */
\r
306 xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
\r
307 configASSERT( xReturned == pdFAIL );
\r
309 /* Notify the task with no action so as not to update the bits even though
\r
310 ULONG_MAX is used as the notification value. */
\r
311 xTaskNotify( xTaskToNotify, ULONG_MAX, eNoAction );
\r
313 /* Reading back the value should should find bit 0 is clear, as this was
\r
314 cleared on entry, but bit 1 is not clear as it will not have been cleared on
\r
315 exit as no notification was received. */
\r
316 xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
\r
317 configASSERT( xReturned == pdPASS );
\r
318 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) );
\r
324 /*--------------------------------------------------------------------------
\r
325 Now try clearing the bit on exit. For that to happen a notification must be
\r
326 received, so the task is notified first. */
\r
327 xTaskNotify( xTaskToNotify, 0, eNoAction );
\r
328 xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
\r
330 /* However as the bit is cleared on exit, after the returned notification
\r
331 value is set, the returned notification value should not have the bit
\r
333 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) );
\r
335 /* ...but reading the value back again should find that the bit was indeed
\r
336 cleared internally. The returned value should be pdFAIL however as nothing
\r
337 has notified the task in the mean time. */
\r
338 xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
\r
339 configASSERT( xReturned == pdFAIL );
\r
340 configASSERT( ulNotifiedValue == ( ULONG_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
344 /* Incremented to show the task is still running. */
\r
345 ulNotifyCycleCount++;
\r
347 /* Leave all bits cleared. */
\r
348 xTaskNotifyWait( ULONG_MAX, 0, NULL, 0 );
\r
350 /*-----------------------------------------------------------*/
\r
352 static void prvNotifyingTimer( TimerHandle_t xTimer )
\r
356 xTaskNotifyGive( xTaskToNotify );
\r
358 /* This value is also incremented from an interrupt. */
\r
359 taskENTER_CRITICAL();
\r
361 ulTimerNotificationsSent++;
\r
363 taskEXIT_CRITICAL();
\r
365 /*-----------------------------------------------------------*/
\r
367 static void prvNotifiedTask( void *pvParameters )
\r
369 const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
\r
370 TickType_t xPeriod;
\r
372 /* Remove compiler warnings about unused parameters. */
\r
373 ( void ) pvParameters;
\r
375 /* Run a few tests that can be done from a single task before entering the
\r
377 prvSingleTaskTests();
\r
379 /* Create the software timer that is used to send notifications to this
\r
380 task. Notifications are also received from an interrupt. */
\r
381 xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
\r
385 /* Start the timer again with a different period. Sometimes the period
\r
386 will be higher than the tasks block time, sometimes it will be lower
\r
387 than the tasks block time. */
\r
388 xPeriod = prvRand() % xMaxPeriod;
\r
389 if( xPeriod < xMinPeriod )
\r
391 xPeriod = xMinPeriod;
\r
394 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
\r
395 xTimerStart( xTimer, portMAX_DELAY );
\r
397 /* Block waiting for the notification again with a different period.
\r
398 Sometimes the period will be higher than the tasks block time, sometimes
\r
399 it will be lower than the tasks block time. */
\r
400 xPeriod = prvRand() % xMaxPeriod;
\r
401 if( xPeriod < xMinPeriod )
\r
403 xPeriod = xMinPeriod;
\r
406 /* Block to wait for a notification but without clearing the
\r
407 notification count, so only add one to the count of received
\r
408 notifications as any other notifications will remain pending. */
\r
409 if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
\r
411 ulTimerNotificationsReceived++;
\r
415 /* Take a notification without clearing again, but this time without a
\r
416 block time specified. */
\r
417 if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
\r
419 ulTimerNotificationsReceived++;
\r
422 /* Wait for the next notification from the timer, clearing all
\r
423 notifications if one is received, so this time adding the total number
\r
424 of notifications that were pending as none will be left pending after
\r
425 the function call. */
\r
426 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
\r
428 /* Wait for the next notification again, clearing all notifications if
\r
429 one is received, but this time blocking indefinitely. */
\r
430 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
432 /* Incremented to show the task is still running. */
\r
433 ulNotifyCycleCount++;
\r
436 /*-----------------------------------------------------------*/
\r
438 void xNotifyTaskFromISR( void )
\r
440 static BaseType_t xCallCount = 0;
\r
441 const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
\r
443 /* The task performs some tests before starting the timer that gives the
\r
444 notification from this interrupt. If the timer has not been created yet
\r
445 then the initial tests have not yet completed and the notification should
\r
447 if( xTimer != NULL )
\r
451 if( xCallCount >= xCallInterval )
\r
453 /* It is time to 'give' the notification again. */
\r
456 xTaskNotifyGiveFromISR( xTaskToNotify, NULL );
\r
457 ulTimerNotificationsSent++;
\r
461 /*-----------------------------------------------------------*/
\r
463 /* This is called to check the created tasks are still running and have not
\r
464 detected any errors. */
\r
465 BaseType_t xAreTaskNotificationTasksStillRunning( void )
\r
467 static uint32_t ulLastNotifyCycleCount = 0;
\r
468 const uint32_t ulMaxSendReceiveDeviation = 5UL;
\r
470 /* Check the cycle count is still incrementing to ensure the task is still
\r
471 actually running. */
\r
472 if( ulLastNotifyCycleCount == ulNotifyCycleCount )
\r
474 xErrorStatus = pdFAIL;
\r
478 ulLastNotifyCycleCount = ulNotifyCycleCount;
\r
481 /* Check the count of 'takes' from the software timer is keeping track with
\r
482 the amount of 'gives'. */
\r
483 if( ulTimerNotificationsSent > ulTimerNotificationsSent )
\r
485 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
\r
487 xErrorStatus = pdFAIL;
\r
491 return xErrorStatus;
\r
493 /*-----------------------------------------------------------*/
\r
495 static UBaseType_t prvRand( void )
\r
497 static uint32_t ulNextRand = ( uint32_t ) prvRand;
\r
499 const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
\r
501 /* Utility function to generate a pseudo random number. */
\r
502 ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
\r
503 return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
\r
505 /*-----------------------------------------------------------*/
\r