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
30 * Tests the behaviour of direct task notifications.
\r
33 /* Standard includes. */
\r
36 /* Scheduler include files. */
\r
37 #include "FreeRTOS.h"
\r
41 /* Demo program include files. */
\r
42 #include "TaskNotify.h"
\r
44 /* Allow parameters to be overridden on a demo by demo basis. */
\r
45 #ifndef notifyNOTIFIED_TASK_STACK_SIZE
\r
46 #define notifyNOTIFIED_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
\r
49 #define notifyTASK_PRIORITY ( tskIDLE_PRIORITY )
\r
50 #define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff )
\r
51 #define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )
\r
53 /*-----------------------------------------------------------*/
\r
56 * Implementation of the task that gets notified.
\r
58 static void prvNotifiedTask( void *pvParameters );
\r
61 * Performs a few initial tests that can be done prior to creating the second
\r
64 static void prvSingleTaskTests( void );
\r
67 * Software timer callback function from which xTaskNotify() is called.
\r
69 static void prvNotifyingTimer( TimerHandle_t xTimer );
\r
72 * Utility function to create pseudo random numbers.
\r
74 static UBaseType_t prvRand( void );
\r
77 * Callback for a timer that is used during preliminary testing. The timer
\r
78 * tests the behaviour when 1: a task waiting for a notification is suspended
\r
79 * and then resumed without ever receiving a notification, and 2: when a task
\r
80 * waiting for a notification receives a notification while it is suspended.
\r
82 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );
\r
84 /*-----------------------------------------------------------*/
\r
86 /* Used to latch errors during the test's execution. */
\r
87 static BaseType_t xErrorStatus = pdPASS;
\r
89 /* Used to ensure the task has not stalled. */
\r
90 static volatile uint32_t ulNotifyCycleCount = 0;
\r
92 /* The handle of the task that receives the notifications. */
\r
93 static TaskHandle_t xTaskToNotify = NULL;
\r
95 /* Used to count the notifications sent to the task from a software timer and
\r
96 the number of notifications received by the task from the software timer. The
\r
97 two should stay synchronised. */
\r
98 static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
\r
100 /* The timer used to notify the task. */
\r
101 static TimerHandle_t xTimer = NULL;
\r
103 /* Used by the pseudo random number generating function. */
\r
104 static size_t uxNextRand = 0;
\r
106 /*-----------------------------------------------------------*/
\r
108 void vStartTaskNotifyTask( void )
\r
110 /* Create the task that performs some tests by itself, then loops around
\r
111 being notified by both a software timer and an interrupt. */
\r
112 xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
\r
113 "Notified", /* Text name for the task - for debugging only - not used by the kernel. */
\r
114 notifyNOTIFIED_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
\r
115 NULL, /* Task parameter, not used in this case. */
\r
116 notifyTASK_PRIORITY, /* Task priority, 0 is the lowest. */
\r
117 &xTaskToNotify ); /* Used to pass a handle to the task out is needed, otherwise set to NULL. */
\r
119 /* Pseudo seed the random number generator. */
\r
120 uxNextRand = ( size_t ) prvRand;
\r
122 /*-----------------------------------------------------------*/
\r
124 static void prvSingleTaskTests( void )
\r
126 const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
\r
127 BaseType_t xReturned;
\r
128 uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;
\r
129 TickType_t xTimeOnEntering;
\r
130 const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
\r
131 const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
\r
132 TimerHandle_t xSingleTaskTimer;
\r
135 /* ------------------------------------------------------------------------
\r
136 Check blocking when there are no notifications. */
\r
137 xTimeOnEntering = xTaskGetTickCount();
\r
138 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
139 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
141 /* Should have blocked for the entire block time. */
\r
142 if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
\r
144 xErrorStatus = pdFAIL;
\r
146 configASSERT( xReturned == pdFAIL );
\r
147 configASSERT( ulNotifiedValue == 0UL );
\r
148 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
149 ( void ) ulNotifiedValue;
\r
154 /* ------------------------------------------------------------------------
\r
155 Check no blocking when notifications are pending. First notify itself -
\r
156 this would not be a normal thing to do and is done here for test purposes
\r
158 xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
\r
160 /* Even through the 'without overwrite' action was used the update should
\r
161 have been successful. */
\r
162 configASSERT( xReturned == pdPASS );
\r
163 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
165 /* No bits should have been pending previously. */
\r
166 configASSERT( ulPreviousValue == 0 );
\r
167 ( void ) ulPreviousValue;
\r
169 /* The task should now have a notification pending, and so not time out. */
\r
170 xTimeOnEntering = xTaskGetTickCount();
\r
171 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
173 if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
\r
175 xErrorStatus = pdFAIL;
\r
178 /* The task should have been notified, and the notified value should
\r
179 be equal to ulFirstNotifiedConst. */
\r
180 configASSERT( xReturned == pdPASS );
\r
181 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
182 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
183 ( void ) ulNotifiedValue;
\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
199 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
201 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
\r
202 configASSERT( xReturned == pdFAIL );
\r
203 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
205 /* Waiting for the notification should now return immediately so a block
\r
206 time of zero is used. */
\r
207 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
209 configASSERT( xReturned == pdPASS );
\r
210 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
211 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
212 ( void ) ulNotifiedValue;
\r
218 /*-------------------------------------------------------------------------
\r
219 Do the same again, only this time use the overwriting version. This time
\r
220 both notifications should pass, and the value written the second time should
\r
221 overwrite the value written the first time, and so be the value that is read
\r
223 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
\r
224 configASSERT( xReturned == pdPASS );
\r
225 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
226 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
\r
227 configASSERT( xReturned == pdPASS );
\r
228 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
229 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
230 configASSERT( xReturned == pdPASS );
\r
231 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
232 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
233 ( void ) ulNotifiedValue;
\r
238 /*-------------------------------------------------------------------------
\r
239 Check notifications with no action pass without updating the value. Even
\r
240 though ulFirstNotifiedConst is used as the value the value read back should
\r
241 remain at ulSecondNotifiedConst. */
\r
242 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
\r
243 configASSERT( xReturned == pdPASS );
\r
244 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
245 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
246 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
247 ( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */
\r
252 /*-------------------------------------------------------------------------
\r
253 Check incrementing values. Send ulMaxLoop increment notifications, then
\r
254 ensure the received value is as expected - which should be
\r
255 ulSecondNotificationValueConst plus how ever many times to loop iterated. */
\r
256 for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
\r
258 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
\r
259 configASSERT( xReturned == pdPASS );
\r
260 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
263 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
264 configASSERT( xReturned == pdPASS );
\r
265 configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
\r
266 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
267 ( void ) ulNotifiedValue;
\r
269 /* Should not be any notifications pending now. */
\r
270 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
271 configASSERT( xReturned == pdFAIL );
\r
272 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
273 ( void ) ulNotifiedValue;
\r
278 /*-------------------------------------------------------------------------
\r
279 Check all bits can be set by notifying the task with one additional bit set
\r
280 on each notification, and exiting the loop when all the bits are found to be
\r
281 set. As there are 32-bits the loop should execute 32 times before all the
\r
282 bits are found to be set. */
\r
283 ulNotifyingValue = 0x01;
\r
286 /* Start with all bits clear. */
\r
287 xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
291 /* Set the next bit in the task's notified value. */
\r
292 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
\r
294 /* Wait for the notified value - which of course will already be
\r
295 available. Don't clear the bits on entry or exit as this loop is exited
\r
296 when all the bits are set. */
\r
297 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
298 configASSERT( xReturned == pdPASS );
\r
299 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
303 /* Use the next bit on the next iteration around this loop. */
\r
304 ulNotifyingValue <<= 1UL;
\r
306 } while ( ulNotifiedValue != notifyUINT32_MAX );
\r
308 /* As a 32-bit value was used the loop should have executed 32 times before
\r
309 all the bits were set. */
\r
310 configASSERT( ulLoop == 32 );
\r
315 /*-------------------------------------------------------------------------
\r
316 Check bits are cleared on entry but not on exit when a notification fails
\r
317 to arrive before timing out - both with and without a timeout value. Wait
\r
318 for the notification again - but this time it is not given by anything and
\r
319 should return pdFAIL. The parameters are set to clear bit zero on entry and
\r
320 bit one on exit. As no notification was received only the bit cleared on
\r
321 entry should actually get cleared. */
\r
322 xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
\r
323 configASSERT( xReturned == pdFAIL );
\r
324 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
326 /* Notify the task with no action so as not to update the bits even though
\r
327 notifyUINT32_MAX is used as the notification value. */
\r
328 xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
\r
330 /* Reading back the value should should find bit 0 is clear, as this was
\r
331 cleared on entry, but bit 1 is not clear as it will not have been cleared on
\r
332 exit as no notification was received. */
\r
333 xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
\r
334 configASSERT( xReturned == pdPASS );
\r
335 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
\r
336 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
342 /*-------------------------------------------------------------------------
\r
343 Now try clearing the bit on exit. For that to happen a notification must be
\r
344 received, so the task is notified first. */
\r
345 xTaskNotify( xTaskToNotify, 0, eNoAction );
\r
346 xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
\r
348 /* However as the bit is cleared on exit, after the returned notification
\r
349 value is set, the returned notification value should not have the bit
\r
351 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
\r
353 /* ...but reading the value back again should find that the bit was indeed
\r
354 cleared internally. The returned value should be pdFAIL however as nothing
\r
355 has notified the task in the mean time. */
\r
356 xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
\r
357 configASSERT( xReturned == pdFAIL );
\r
358 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
359 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
364 /*-------------------------------------------------------------------------
\r
365 Now try querying the previous value while notifying a task. */
\r
366 xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
\r
367 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
369 /* Clear all bits. */
\r
370 xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
\r
371 xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
\r
372 configASSERT( ulPreviousValue == 0 );
\r
374 ulExpectedValue = 0;
\r
375 for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
\r
377 /* Set the next bit up, and expect to receive the last bits set (so
\r
378 the previous value will not yet have the bit being set this time
\r
380 xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
\r
381 configASSERT( ulExpectedValue == ulPreviousValue );
\r
382 ulExpectedValue |= ulLoop;
\r
387 /* ------------------------------------------------------------------------
\r
388 Clear the previous notifications. */
\r
389 xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
391 /* The task should not have any notifications pending, so an attempt to clear
\r
392 the notification state should fail. */
\r
393 configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
\r
395 /* Get the task to notify itself. This is not a normal thing to do, and is
\r
396 only done here for test purposes. */
\r
397 xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
\r
399 /* Now the notification state should be eNotified, so it should now be
\r
400 possible to clear the notification state. */
\r
401 configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
\r
402 configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
\r
406 /* ------------------------------------------------------------------------
\r
407 Create a timer that will try notifying this task while it is suspended. */
\r
408 xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
\r
409 configASSERT( xSingleTaskTimer );
\r
411 /* Incremented to show the task is still running. */
\r
412 ulNotifyCycleCount++;
\r
414 /* Ensure no notifications are pending. */
\r
415 xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
\r
417 /* Raise the task's priority so it can suspend itself before the timer
\r
419 vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
\r
421 /* Start the timer that will try notifying this task while it is
\r
422 suspended, then wait for a notification. The first time the callback
\r
423 executes the timer will suspend the task, then resume the task, without
\r
424 ever sending a notification to the task. */
\r
425 ulNotifiedValue = 0;
\r
426 xTimerStart( xSingleTaskTimer, portMAX_DELAY );
\r
428 /* Check a notification is not received. */
\r
429 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
\r
430 configASSERT( xReturned == pdFALSE );
\r
431 configASSERT( ulNotifiedValue == 0 );
\r
432 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
434 /* Incremented to show the task is still running. */
\r
435 ulNotifyCycleCount++;
\r
437 /* Start the timer that will try notifying this task while it is
\r
438 suspended, then wait for a notification. The second time the callback
\r
439 executes the timer will suspend the task, notify the task, then resume the
\r
440 task (previously it was suspended and resumed without being notified). */
\r
441 xTimerStart( xSingleTaskTimer, portMAX_DELAY );
\r
443 /* Check a notification is received. */
\r
444 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
\r
445 configASSERT( xReturned == pdPASS );
\r
446 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
447 configASSERT( ulNotifiedValue != 0 );
\r
449 /* Return the task to its proper priority and delete the timer as it is
\r
451 vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
\r
452 xTimerDelete( xSingleTaskTimer, portMAX_DELAY );
\r
454 /* Incremented to show the task is still running. */
\r
455 ulNotifyCycleCount++;
\r
457 /* Leave all bits cleared. */
\r
458 xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
\r
460 /*-----------------------------------------------------------*/
\r
462 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )
\r
464 static uint32_t ulCallCount = 0;
\r
466 /* Remove compiler warnings about unused parameters. */
\r
467 ( void ) xExpiredTimer;
\r
469 /* Callback for a timer that is used during preliminary testing. The timer
\r
470 tests the behaviour when 1: a task waiting for a notification is suspended
\r
471 and then resumed without ever receiving a notification, and 2: when a task
\r
472 waiting for a notification receives a notification while it is suspended. */
\r
474 if( ulCallCount == 0 )
\r
476 vTaskSuspend( xTaskToNotify );
\r
477 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
\r
478 vTaskResume( xTaskToNotify );
\r
482 vTaskSuspend( xTaskToNotify );
\r
484 /* Sending a notification while the task is suspended should pass, but
\r
485 not cause the task to resume. ulCallCount is just used as a convenient
\r
487 xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );
\r
489 /* Make sure giving the notification didn't resume the task. */
\r
490 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
\r
492 vTaskResume( xTaskToNotify );
\r
497 /*-----------------------------------------------------------*/
\r
499 static void prvNotifyingTimer( TimerHandle_t xNotUsed )
\r
503 xTaskNotifyGive( xTaskToNotify );
\r
505 /* This value is also incremented from an interrupt. */
\r
506 taskENTER_CRITICAL();
\r
508 ulTimerNotificationsSent++;
\r
510 taskEXIT_CRITICAL();
\r
512 /*-----------------------------------------------------------*/
\r
514 static void prvNotifiedTask( void *pvParameters )
\r
516 const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
\r
517 TickType_t xPeriod;
\r
518 const uint32_t ulCyclesToRaisePriority = 50UL;
\r
520 /* Remove compiler warnings about unused parameters. */
\r
521 ( void ) pvParameters;
\r
523 /* Run a few tests that can be done from a single task before entering the
\r
525 prvSingleTaskTests();
\r
527 /* Create the software timer that is used to send notifications to this
\r
528 task. Notifications are also received from an interrupt. */
\r
529 xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
\r
533 /* Start the timer again with a different period. Sometimes the period
\r
534 will be higher than the task's block time, sometimes it will be lower
\r
535 than the task's block time. */
\r
536 xPeriod = prvRand() % xMaxPeriod;
\r
537 if( xPeriod < xMinPeriod )
\r
539 xPeriod = xMinPeriod;
\r
542 /* Change the timer period and start the timer. */
\r
543 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
\r
545 /* Block waiting for the notification again with a different period.
\r
546 Sometimes the period will be higher than the task's block time,
\r
547 sometimes it will be lower than the task's block time. */
\r
548 xPeriod = prvRand() % xMaxPeriod;
\r
549 if( xPeriod < xMinPeriod )
\r
551 xPeriod = xMinPeriod;
\r
554 /* Block to wait for a notification but without clearing the
\r
555 notification count, so only add one to the count of received
\r
556 notifications as any other notifications will remain pending. */
\r
557 if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
\r
559 ulTimerNotificationsReceived++;
\r
563 /* Take a notification without clearing again, but this time without a
\r
564 block time specified. */
\r
565 if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
\r
567 ulTimerNotificationsReceived++;
\r
570 /* Wait for the next notification from the timer, clearing all
\r
571 notifications if one is received, so this time adding the total number
\r
572 of notifications that were pending as none will be left pending after
\r
573 the function call. */
\r
574 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
\r
576 /* Occasionally raise the priority of the task being notified to test
\r
577 the path where the task is notified from an ISR and becomes the highest
\r
578 priority ready state task, but the pxHigherPriorityTaskWoken parameter
\r
579 is NULL (which it is in the tick hook that sends notifications to this
\r
581 if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
\r
583 vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
\r
585 /* Wait for the next notification again, clearing all notifications
\r
586 if one is received, but this time blocking indefinitely. */
\r
587 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
589 /* Reset the priority. */
\r
590 vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );
\r
594 /* Wait for the next notification again, clearing all notifications
\r
595 if one is received, but this time blocking indefinitely. */
\r
596 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
599 /* Incremented to show the task is still running. */
\r
600 ulNotifyCycleCount++;
\r
603 /*-----------------------------------------------------------*/
\r
605 void xNotifyTaskFromISR( void )
\r
607 static BaseType_t xCallCount = 0, xAPIToUse = 0;
\r
608 const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
\r
609 uint32_t ulPreviousValue;
\r
610 const uint32_t ulUnexpectedValue = 0xff;
\r
612 /* Check the task notification demo tasks were actually created. */
\r
613 configASSERT( xTaskToNotify );
\r
615 /* The task performs some tests before starting the timer that gives the
\r
616 notification from this interrupt. If the timer has not been created yet
\r
617 then the initial tests have not yet completed and the notification should
\r
619 if( xTimer != NULL )
\r
623 if( xCallCount >= xCallInterval )
\r
625 /* It is time to 'give' the notification again. */
\r
628 /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
\r
629 and xTaskNotifyAndQueryFromISR(). */
\r
630 switch( xAPIToUse )
\r
632 case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
\r
636 case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
\r
640 case 2: ulPreviousValue = ulUnexpectedValue;
\r
641 xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
\r
642 configASSERT( ulPreviousValue != ulUnexpectedValue );
\r
646 default:/* Should never get here!. */
\r
650 ulTimerNotificationsSent++;
\r
654 /*-----------------------------------------------------------*/
\r
656 /* This is called to check the created tasks are still running and have not
\r
657 detected any errors. */
\r
658 BaseType_t xAreTaskNotificationTasksStillRunning( void )
\r
660 static uint32_t ulLastNotifyCycleCount = 0;
\r
661 const uint32_t ulMaxSendReceiveDeviation = 5UL;
\r
663 /* Check the cycle count is still incrementing to ensure the task is still
\r
664 actually running. */
\r
665 if( ulLastNotifyCycleCount == ulNotifyCycleCount )
\r
667 xErrorStatus = pdFAIL;
\r
671 ulLastNotifyCycleCount = ulNotifyCycleCount;
\r
674 /* Check the count of 'takes' from the software timer is keeping track with
\r
675 the amount of 'gives'. */
\r
676 if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
\r
678 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
\r
680 xErrorStatus = pdFAIL;
\r
684 return xErrorStatus;
\r
686 /*-----------------------------------------------------------*/
\r
688 static UBaseType_t prvRand( void )
\r
690 const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;
\r
692 /* Utility function to generate a pseudo random number. */
\r
693 uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;
\r
694 return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );
\r
696 /*-----------------------------------------------------------*/
\r