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
51 /* Constants used in tests when setting/clearing bits. */
\r
52 #define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff )
\r
53 #define notifyUINT32_HIGH_BYTE ( ( uint32_t ) 0xff000000 )
\r
54 #define notifyUINT32_LOW_BYTE ( ( uint32_t ) 0x000000ff )
\r
56 #define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )
\r
58 /*-----------------------------------------------------------*/
\r
61 * Implementation of the task that gets notified.
\r
63 static void prvNotifiedTask( void *pvParameters );
\r
66 * Performs a few initial tests that can be done prior to creating the second
\r
69 static void prvSingleTaskTests( void );
\r
72 * Software timer callback function from which xTaskNotify() is called.
\r
74 static void prvNotifyingTimer( TimerHandle_t xTimer );
\r
77 * Utility function to create pseudo random numbers.
\r
79 static UBaseType_t prvRand( void );
\r
82 * Callback for a timer that is used during preliminary testing. The timer
\r
83 * tests the behaviour when 1: a task waiting for a notification is suspended
\r
84 * and then resumed without ever receiving a notification, and 2: when a task
\r
85 * waiting for a notification receives a notification while it is suspended.
\r
87 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );
\r
89 /*-----------------------------------------------------------*/
\r
91 /* Used to latch errors during the test's execution. */
\r
92 static BaseType_t xErrorStatus = pdPASS;
\r
94 /* Used to ensure the task has not stalled. */
\r
95 static volatile uint32_t ulNotifyCycleCount = 0;
\r
97 /* The handle of the task that receives the notifications. */
\r
98 static TaskHandle_t xTaskToNotify = NULL;
\r
100 /* Used to count the notifications sent to the task from a software timer and
\r
101 the number of notifications received by the task from the software timer. The
\r
102 two should stay synchronised. */
\r
103 static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
\r
105 /* The timer used to notify the task. */
\r
106 static TimerHandle_t xTimer = NULL;
\r
108 /* Used by the pseudo random number generating function. */
\r
109 static size_t uxNextRand = 0;
\r
111 /*-----------------------------------------------------------*/
\r
113 void vStartTaskNotifyTask( void )
\r
115 /* Create the task that performs some tests by itself, then loops around
\r
116 being notified by both a software timer and an interrupt. */
\r
117 xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
\r
118 "Notified", /* Text name for the task - for debugging only - not used by the kernel. */
\r
119 notifyNOTIFIED_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
\r
120 NULL, /* Task parameter, not used in this case. */
\r
121 notifyTASK_PRIORITY, /* Task priority, 0 is the lowest. */
\r
122 &xTaskToNotify ); /* Used to pass a handle to the task out is needed, otherwise set to NULL. */
\r
124 /* Pseudo seed the random number generator. */
\r
125 uxNextRand = ( size_t ) prvRand;
\r
127 /*-----------------------------------------------------------*/
\r
129 static void prvSingleTaskTests( void )
\r
131 const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
\r
132 BaseType_t xReturned;
\r
133 uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;
\r
134 TickType_t xTimeOnEntering;
\r
135 const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
\r
136 const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
\r
137 TimerHandle_t xSingleTaskTimer;
\r
140 /* ------------------------------------------------------------------------
\r
141 Check blocking when there are no notifications. */
\r
142 xTimeOnEntering = xTaskGetTickCount();
\r
143 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
144 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
146 /* Should have blocked for the entire block time. */
\r
147 if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
\r
149 xErrorStatus = pdFAIL;
\r
151 configASSERT( xReturned == pdFAIL );
\r
152 configASSERT( ulNotifiedValue == 0UL );
\r
153 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
154 ( void ) ulNotifiedValue;
\r
159 /* ------------------------------------------------------------------------
\r
160 Check no blocking when notifications are pending. First notify itself -
\r
161 this would not be a normal thing to do and is done here for test purposes
\r
163 xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
\r
165 /* Even through the 'without overwrite' action was used the update should
\r
166 have been successful. */
\r
167 configASSERT( xReturned == pdPASS );
\r
168 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
170 /* No bits should have been pending previously. */
\r
171 configASSERT( ulPreviousValue == 0 );
\r
172 ( void ) ulPreviousValue;
\r
174 /* The task should now have a notification pending, and so not time out. */
\r
175 xTimeOnEntering = xTaskGetTickCount();
\r
176 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
\r
178 if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
\r
180 xErrorStatus = pdFAIL;
\r
183 /* The task should have been notified, and the notified value should
\r
184 be equal to ulFirstNotifiedConst. */
\r
185 configASSERT( xReturned == pdPASS );
\r
186 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
187 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
188 ( void ) ulNotifiedValue;
\r
190 /* Incremented to show the task is still running. */
\r
191 ulNotifyCycleCount++;
\r
197 /*-------------------------------------------------------------------------
\r
198 Check the non-overwriting functionality. The notification is done twice
\r
199 using two different notification values. The action says don't overwrite so
\r
200 only the first notification should pass and the value read back should also
\r
201 be that used with the first notification. */
\r
202 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
\r
203 configASSERT( xReturned == pdPASS );
\r
204 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
206 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
\r
207 configASSERT( xReturned == pdFAIL );
\r
208 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
210 /* Waiting for the notification should now return immediately so a block
\r
211 time of zero is used. */
\r
212 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
214 configASSERT( xReturned == pdPASS );
\r
215 configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
\r
216 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
217 ( void ) ulNotifiedValue;
\r
223 /*-------------------------------------------------------------------------
\r
224 Do the same again, only this time use the overwriting version. This time
\r
225 both notifications should pass, and the value written the second time should
\r
226 overwrite the value written the first time, and so be the value that is read
\r
228 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
\r
229 configASSERT( xReturned == pdPASS );
\r
230 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
231 xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
\r
232 configASSERT( xReturned == pdPASS );
\r
233 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
234 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
235 configASSERT( xReturned == pdPASS );
\r
236 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
237 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
238 ( void ) ulNotifiedValue;
\r
243 /*-------------------------------------------------------------------------
\r
244 Check notifications with no action pass without updating the value. Even
\r
245 though ulFirstNotifiedConst is used as the value the value read back should
\r
246 remain at ulSecondNotifiedConst. */
\r
247 xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
\r
248 configASSERT( xReturned == pdPASS );
\r
249 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
250 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
251 configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
\r
252 ( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */
\r
257 /*-------------------------------------------------------------------------
\r
258 Check incrementing values. Send ulMaxLoop increment notifications, then
\r
259 ensure the received value is as expected - which should be
\r
260 ulSecondNotificationValueConst plus how ever many times to loop iterated. */
\r
261 for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
\r
263 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
\r
264 configASSERT( xReturned == pdPASS );
\r
265 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
268 xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
269 configASSERT( xReturned == pdPASS );
\r
270 configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
\r
271 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
272 ( void ) ulNotifiedValue;
\r
274 /* Should not be any notifications pending now. */
\r
275 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
276 configASSERT( xReturned == pdFAIL );
\r
277 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
278 ( void ) ulNotifiedValue;
\r
283 /*-------------------------------------------------------------------------
\r
284 Check all bits can be set by notifying the task with one additional bit set
\r
285 on each notification, and exiting the loop when all the bits are found to be
\r
286 set. As there are 32-bits the loop should execute 32 times before all the
\r
287 bits are found to be set. */
\r
288 ulNotifyingValue = 0x01;
\r
291 /* Start with all bits clear. */
\r
292 xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
296 /* Set the next bit in the task's notified value. */
\r
297 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
\r
299 /* Wait for the notified value - which of course will already be
\r
300 available. Don't clear the bits on entry or exit as this loop is exited
\r
301 when all the bits are set. */
\r
302 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
\r
303 configASSERT( xReturned == pdPASS );
\r
304 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
308 /* Use the next bit on the next iteration around this loop. */
\r
309 ulNotifyingValue <<= 1UL;
\r
311 } while ( ulNotifiedValue != notifyUINT32_MAX );
\r
313 /* As a 32-bit value was used the loop should have executed 32 times before
\r
314 all the bits were set. */
\r
315 configASSERT( ulLoop == 32 );
\r
320 /*-------------------------------------------------------------------------
\r
321 Check bits are cleared on entry but not on exit when a notification fails
\r
322 to arrive before timing out - both with and without a timeout value. Wait
\r
323 for the notification again - but this time it is not given by anything and
\r
324 should return pdFAIL. The parameters are set to clear bit zero on entry and
\r
325 bit one on exit. As no notification was received only the bit cleared on
\r
326 entry should actually get cleared. */
\r
327 xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
\r
328 configASSERT( xReturned == pdFAIL );
\r
329 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
331 /* Notify the task with no action so as not to update the bits even though
\r
332 notifyUINT32_MAX is used as the notification value. */
\r
333 xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
\r
335 /* Reading back the value should should find bit 0 is clear, as this was
\r
336 cleared on entry, but bit 1 is not clear as it will not have been cleared on
\r
337 exit as no notification was received. */
\r
338 xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
\r
339 configASSERT( xReturned == pdPASS );
\r
340 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
\r
341 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
347 /*-------------------------------------------------------------------------
\r
348 Now try clearing the bit on exit. For that to happen a notification must be
\r
349 received, so the task is notified first. */
\r
350 xTaskNotify( xTaskToNotify, 0, eNoAction );
\r
351 xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
\r
353 /* However as the bit is cleared on exit, after the returned notification
\r
354 value is set, the returned notification value should not have the bit
\r
356 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
\r
358 /* ...but reading the value back again should find that the bit was indeed
\r
359 cleared internally. The returned value should be pdFAIL however as nothing
\r
360 has notified the task in the mean time. */
\r
361 xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
\r
362 configASSERT( xReturned == pdFAIL );
\r
363 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
364 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
369 /*-------------------------------------------------------------------------
\r
370 Now try querying the previous value while notifying a task. */
\r
371 xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
\r
372 configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
\r
374 /* Clear all bits. */
\r
375 xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
\r
376 xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
\r
377 configASSERT( ulPreviousValue == 0 );
\r
379 ulExpectedValue = 0;
\r
380 for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
\r
382 /* Set the next bit up, and expect to receive the last bits set (so
\r
383 the previous value will not yet have the bit being set this time
\r
385 xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
\r
386 configASSERT( ulExpectedValue == ulPreviousValue );
\r
387 ulExpectedValue |= ulLoop;
\r
392 /* ------------------------------------------------------------------------
\r
393 Clear the previous notifications. */
\r
394 xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
\r
396 /* The task should not have any notifications pending, so an attempt to clear
\r
397 the notification state should fail. */
\r
398 configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
\r
400 /* Get the task to notify itself. This is not a normal thing to do, and is
\r
401 only done here for test purposes. */
\r
402 xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
\r
404 /* Now the notification state should be eNotified, so it should now be
\r
405 possible to clear the notification state. */
\r
406 configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
\r
407 configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
\r
411 /* ------------------------------------------------------------------------
\r
412 Clear bits in the notification value. */
\r
414 /* Get the task to set all bits its own notification value. This is not a
\r
415 normal thing to do, and is only done here for test purposes. */
\r
416 xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eSetBits );
\r
418 /* Now clear the top bytes - the returned value from the first call should
\r
419 indicate that previously all bits were set. */
\r
420 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX );
\r
422 /* Next clear the bottom bytes - the returned value this time should indicate
\r
423 that the top byte was clear (before the bottom byte was cleared. */
\r
424 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) );
\r
426 /* Next clear all bytes - the returned value should indicate that previously the
\r
427 high and low bytes were clear. */
\r
428 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
\r
430 /* Now all bits should be clear. */
\r
431 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
\r
432 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, 0UL ) == 0 );
\r
433 configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
\r
435 /* Now the notification state should be eNotified, so it should now be
\r
436 possible to clear the notification state. */
\r
437 configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
\r
438 configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
\r
442 /* ------------------------------------------------------------------------
\r
443 Create a timer that will try notifying this task while it is suspended. */
\r
444 xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
\r
445 configASSERT( xSingleTaskTimer );
\r
447 /* Incremented to show the task is still running. */
\r
448 ulNotifyCycleCount++;
\r
450 /* Ensure no notifications are pending. */
\r
451 xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
\r
453 /* Raise the task's priority so it can suspend itself before the timer
\r
455 vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
\r
457 /* Start the timer that will try notifying this task while it is
\r
458 suspended, then wait for a notification. The first time the callback
\r
459 executes the timer will suspend the task, then resume the task, without
\r
460 ever sending a notification to the task. */
\r
461 ulNotifiedValue = 0;
\r
462 xTimerStart( xSingleTaskTimer, portMAX_DELAY );
\r
464 /* Check a notification is not received. */
\r
465 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
\r
466 configASSERT( xReturned == pdFALSE );
\r
467 configASSERT( ulNotifiedValue == 0 );
\r
468 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
470 /* Incremented to show the task is still running. */
\r
471 ulNotifyCycleCount++;
\r
473 /* Start the timer that will try notifying this task while it is
\r
474 suspended, then wait for a notification. The second time the callback
\r
475 executes the timer will suspend the task, notify the task, then resume the
\r
476 task (previously it was suspended and resumed without being notified). */
\r
477 xTimerStart( xSingleTaskTimer, portMAX_DELAY );
\r
479 /* Check a notification is received. */
\r
480 xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
\r
481 configASSERT( xReturned == pdPASS );
\r
482 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
483 configASSERT( ulNotifiedValue != 0 );
\r
485 /* Return the task to its proper priority and delete the timer as it is
\r
487 vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
\r
488 xTimerDelete( xSingleTaskTimer, portMAX_DELAY );
\r
490 /* Incremented to show the task is still running. */
\r
491 ulNotifyCycleCount++;
\r
493 /* Leave all bits cleared. */
\r
494 xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
\r
496 /*-----------------------------------------------------------*/
\r
498 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )
\r
500 static uint32_t ulCallCount = 0;
\r
502 /* Remove compiler warnings about unused parameters. */
\r
503 ( void ) xExpiredTimer;
\r
505 /* Callback for a timer that is used during preliminary testing. The timer
\r
506 tests the behaviour when 1: a task waiting for a notification is suspended
\r
507 and then resumed without ever receiving a notification, and 2: when a task
\r
508 waiting for a notification receives a notification while it is suspended. */
\r
510 if( ulCallCount == 0 )
\r
512 vTaskSuspend( xTaskToNotify );
\r
513 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
\r
514 vTaskResume( xTaskToNotify );
\r
518 vTaskSuspend( xTaskToNotify );
\r
520 /* Sending a notification while the task is suspended should pass, but
\r
521 not cause the task to resume. ulCallCount is just used as a convenient
\r
523 xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );
\r
525 /* Make sure giving the notification didn't resume the task. */
\r
526 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
\r
528 vTaskResume( xTaskToNotify );
\r
533 /*-----------------------------------------------------------*/
\r
535 static void prvNotifyingTimer( TimerHandle_t xNotUsed )
\r
539 xTaskNotifyGive( xTaskToNotify );
\r
541 /* This value is also incremented from an interrupt. */
\r
542 taskENTER_CRITICAL();
\r
544 ulTimerNotificationsSent++;
\r
546 taskEXIT_CRITICAL();
\r
548 /*-----------------------------------------------------------*/
\r
550 static void prvNotifiedTask( void *pvParameters )
\r
552 const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
\r
553 TickType_t xPeriod;
\r
554 const uint32_t ulCyclesToRaisePriority = 50UL;
\r
556 /* Remove compiler warnings about unused parameters. */
\r
557 ( void ) pvParameters;
\r
559 /* Run a few tests that can be done from a single task before entering the
\r
561 prvSingleTaskTests();
\r
563 /* Create the software timer that is used to send notifications to this
\r
564 task. Notifications are also received from an interrupt. */
\r
565 xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
\r
569 /* Start the timer again with a different period. Sometimes the period
\r
570 will be higher than the task's block time, sometimes it will be lower
\r
571 than the task's block time. */
\r
572 xPeriod = prvRand() % xMaxPeriod;
\r
573 if( xPeriod < xMinPeriod )
\r
575 xPeriod = xMinPeriod;
\r
578 /* Change the timer period and start the timer. */
\r
579 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
\r
581 /* Block waiting for the notification again with a different period.
\r
582 Sometimes the period will be higher than the task's block time,
\r
583 sometimes it will be lower than the task's block time. */
\r
584 xPeriod = prvRand() % xMaxPeriod;
\r
585 if( xPeriod < xMinPeriod )
\r
587 xPeriod = xMinPeriod;
\r
590 /* Block to wait for a notification but without clearing the
\r
591 notification count, so only add one to the count of received
\r
592 notifications as any other notifications will remain pending. */
\r
593 if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
\r
595 ulTimerNotificationsReceived++;
\r
599 /* Take a notification without clearing again, but this time without a
\r
600 block time specified. */
\r
601 if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
\r
603 ulTimerNotificationsReceived++;
\r
606 /* Wait for the next notification from the timer, clearing all
\r
607 notifications if one is received, so this time adding the total number
\r
608 of notifications that were pending as none will be left pending after
\r
609 the function call. */
\r
610 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
\r
612 /* Occasionally raise the priority of the task being notified to test
\r
613 the path where the task is notified from an ISR and becomes the highest
\r
614 priority ready state task, but the pxHigherPriorityTaskWoken parameter
\r
615 is NULL (which it is in the tick hook that sends notifications to this
\r
617 if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
\r
619 vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
\r
621 /* Wait for the next notification again, clearing all notifications
\r
622 if one is received, but this time blocking indefinitely. */
\r
623 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
625 /* Reset the priority. */
\r
626 vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );
\r
630 /* Wait for the next notification again, clearing all notifications
\r
631 if one is received, but this time blocking indefinitely. */
\r
632 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
\r
635 /* Incremented to show the task is still running. */
\r
636 ulNotifyCycleCount++;
\r
639 /*-----------------------------------------------------------*/
\r
641 void xNotifyTaskFromISR( void )
\r
643 static BaseType_t xCallCount = 0, xAPIToUse = 0;
\r
644 const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
\r
645 uint32_t ulPreviousValue;
\r
646 const uint32_t ulUnexpectedValue = 0xff;
\r
648 /* Check the task notification demo tasks were actually created. */
\r
649 configASSERT( xTaskToNotify );
\r
651 /* The task performs some tests before starting the timer that gives the
\r
652 notification from this interrupt. If the timer has not been created yet
\r
653 then the initial tests have not yet completed and the notification should
\r
655 if( xTimer != NULL )
\r
659 if( xCallCount >= xCallInterval )
\r
661 /* It is time to 'give' the notification again. */
\r
664 /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
\r
665 and xTaskNotifyAndQueryFromISR(). */
\r
666 switch( xAPIToUse )
\r
668 case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
\r
672 case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
\r
676 case 2: ulPreviousValue = ulUnexpectedValue;
\r
677 xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
\r
678 configASSERT( ulPreviousValue != ulUnexpectedValue );
\r
682 default:/* Should never get here!. */
\r
686 ulTimerNotificationsSent++;
\r
690 /*-----------------------------------------------------------*/
\r
692 /* This is called to check the created tasks are still running and have not
\r
693 detected any errors. */
\r
694 BaseType_t xAreTaskNotificationTasksStillRunning( void )
\r
696 static uint32_t ulLastNotifyCycleCount = 0;
\r
697 const uint32_t ulMaxSendReceiveDeviation = 5UL;
\r
699 /* Check the cycle count is still incrementing to ensure the task is still
\r
700 actually running. */
\r
701 if( ulLastNotifyCycleCount == ulNotifyCycleCount )
\r
703 xErrorStatus = pdFAIL;
\r
707 ulLastNotifyCycleCount = ulNotifyCycleCount;
\r
710 /* Check the count of 'takes' from the software timer is keeping track with
\r
711 the amount of 'gives'. */
\r
712 if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
\r
714 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
\r
716 xErrorStatus = pdFAIL;
\r
720 return xErrorStatus;
\r
722 /*-----------------------------------------------------------*/
\r
724 static UBaseType_t prvRand( void )
\r
726 const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;
\r
728 /* Utility function to generate a pseudo random number. */
\r
729 uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;
\r
730 return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );
\r
732 /*-----------------------------------------------------------*/
\r