]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/TaskNotify.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / Common / Minimal / TaskNotify.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\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
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 \r
30 /*\r
31  * Tests the behaviour of direct task notifications.\r
32  */\r
33 \r
34 /* Standard includes. */\r
35 #include <limits.h>\r
36 \r
37 /* Scheduler include files. */\r
38 #include "FreeRTOS.h"\r
39 #include "task.h"\r
40 #include "timers.h"\r
41 \r
42 /* Demo program include files. */\r
43 #include "TaskNotify.h"\r
44 \r
45 #define notifyTASK_PRIORITY             ( tskIDLE_PRIORITY )\r
46 #define notifyUINT32_MAX        ( ( uint32_t ) 0xffffffff )\r
47 #define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )\r
48 \r
49 /*-----------------------------------------------------------*/\r
50 \r
51 /*\r
52  * Implementation of the task that gets notified.\r
53  */\r
54 static void prvNotifiedTask( void *pvParameters );\r
55 \r
56 /*\r
57  * Performs a few initial tests that can be done prior to creating the second\r
58  * task.\r
59  */\r
60 static void prvSingleTaskTests( void );\r
61 \r
62 /*\r
63  * Software timer callback function from which xTaskNotify() is called.\r
64  */\r
65 static void prvNotifyingTimer( TimerHandle_t xTimer );\r
66 \r
67 /*\r
68  * Utility function to create pseudo random numbers.\r
69  */\r
70 static UBaseType_t prvRand( void );\r
71 \r
72 /*\r
73  * Callback for a timer that is used during preliminary testing.  The timer\r
74  * tests the behaviour when 1: a task waiting for a notification is suspended\r
75  * and then resumed without ever receiving a notification, and 2: when a task\r
76  * waiting for a notification receives a notification while it is suspended.\r
77  */\r
78 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );\r
79 \r
80 /*-----------------------------------------------------------*/\r
81 \r
82 /* Used to latch errors during the test's execution. */\r
83 static BaseType_t xErrorStatus = pdPASS;\r
84 \r
85 /* Used to ensure the task has not stalled. */\r
86 static volatile uint32_t ulNotifyCycleCount = 0;\r
87 \r
88 /* The handle of the task that receives the notifications. */\r
89 static TaskHandle_t xTaskToNotify = NULL;\r
90 \r
91 /* Used to count the notifications sent to the task from a software timer and\r
92 the number of notifications received by the task from the software timer.  The\r
93 two should stay synchronised. */\r
94 static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;\r
95 \r
96 /* The timer used to notify the task. */\r
97 static TimerHandle_t xTimer = NULL;\r
98 \r
99 /* Used by the pseudo random number generating function. */\r
100 static size_t uxNextRand = 0;\r
101 \r
102 /*-----------------------------------------------------------*/\r
103 \r
104 void vStartTaskNotifyTask( void  )\r
105 {\r
106         /* Create the task that performs some tests by itself, then loops around\r
107         being notified by both a software timer and an interrupt. */\r
108         xTaskCreate( prvNotifiedTask, "Notified", configMINIMAL_STACK_SIZE, NULL, notifyTASK_PRIORITY, &xTaskToNotify );\r
109 \r
110         /* Pseudo seed the random number generator. */\r
111         uxNextRand = ( size_t ) prvRand;\r
112 }\r
113 /*-----------------------------------------------------------*/\r
114 \r
115 static void prvSingleTaskTests( void )\r
116 {\r
117 const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );\r
118 BaseType_t xReturned;\r
119 uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;\r
120 TickType_t xTimeOnEntering;\r
121 const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;\r
122 const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;\r
123 TimerHandle_t xSingleTaskTimer;\r
124 \r
125 \r
126         /* ------------------------------------------------------------------------\r
127         Check blocking when there are no notifications. */\r
128         xTimeOnEntering = xTaskGetTickCount();\r
129         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );\r
130         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
131 \r
132         /* Should have blocked for the entire block time. */\r
133         if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )\r
134         {\r
135                 xErrorStatus = pdFAIL;\r
136         }\r
137         configASSERT( xReturned == pdFAIL );\r
138         configASSERT( ulNotifiedValue == 0UL );\r
139         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
140         ( void ) ulNotifiedValue;\r
141 \r
142 \r
143 \r
144 \r
145         /* ------------------------------------------------------------------------\r
146         Check no blocking when notifications are pending.  First notify itself -\r
147         this would not be a normal thing to do and is done here for test purposes\r
148         only. */\r
149         xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );\r
150 \r
151         /* Even through the 'without overwrite' action was used the update should\r
152         have been successful. */\r
153         configASSERT( xReturned == pdPASS );\r
154         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
155 \r
156         /* No bits should have been pending previously. */\r
157         configASSERT( ulPreviousValue == 0 );\r
158         ( void ) ulPreviousValue;\r
159 \r
160         /* The task should now have a notification pending, and so not time out. */\r
161         xTimeOnEntering = xTaskGetTickCount();\r
162         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );\r
163 \r
164         if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )\r
165         {\r
166                 xErrorStatus = pdFAIL;\r
167         }\r
168 \r
169         /* The task should have been notified, and the notified value should\r
170         be equal to ulFirstNotifiedConst. */\r
171         configASSERT( xReturned == pdPASS );\r
172         configASSERT( ulNotifiedValue == ulFirstNotifiedConst );\r
173         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
174         ( void ) ulNotifiedValue;\r
175 \r
176         /* Incremented to show the task is still running. */\r
177         ulNotifyCycleCount++;\r
178 \r
179 \r
180 \r
181 \r
182 \r
183         /*-------------------------------------------------------------------------\r
184         Check the non-overwriting functionality.  The notification is done twice\r
185         using two different notification values.  The action says don't overwrite so\r
186         only the first notification should pass and the value read back should also\r
187         be that used with the first notification. */\r
188         xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );\r
189         configASSERT( xReturned == pdPASS );\r
190         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
191 \r
192         xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );\r
193         configASSERT( xReturned == pdFAIL );\r
194         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
195 \r
196         /* Waiting for the notification should now return immediately so a block\r
197         time of zero is used. */\r
198         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
199 \r
200         configASSERT( xReturned == pdPASS );\r
201         configASSERT( ulNotifiedValue == ulFirstNotifiedConst );\r
202         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
203         ( void ) ulNotifiedValue;\r
204 \r
205 \r
206 \r
207 \r
208 \r
209         /*-------------------------------------------------------------------------\r
210         Do the same again, only this time use the overwriting version.  This time\r
211         both notifications should pass, and the value written the second time should\r
212         overwrite the value written the first time, and so be the value that is read\r
213         back. */\r
214         xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );\r
215         configASSERT( xReturned == pdPASS );\r
216         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
217         xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );\r
218         configASSERT( xReturned == pdPASS );\r
219         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
220         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
221         configASSERT( xReturned == pdPASS );\r
222         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
223         configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );\r
224         ( void ) ulNotifiedValue;\r
225 \r
226 \r
227 \r
228 \r
229         /*-------------------------------------------------------------------------\r
230         Check notifications with no action pass without updating the value.  Even\r
231         though ulFirstNotifiedConst is used as the value the value read back should\r
232         remain at ulSecondNotifiedConst. */\r
233         xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );\r
234         configASSERT( xReturned == pdPASS );\r
235         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
236         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
237         configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );\r
238         ( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */\r
239 \r
240 \r
241 \r
242 \r
243         /*-------------------------------------------------------------------------\r
244         Check incrementing values.  Send ulMaxLoop increment notifications, then\r
245         ensure the received value is as expected - which should be\r
246         ulSecondNotificationValueConst plus how ever many times to loop iterated. */\r
247         for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )\r
248         {\r
249                 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );\r
250                 configASSERT( xReturned == pdPASS );\r
251                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
252         }\r
253 \r
254         xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
255         configASSERT( xReturned == pdPASS );\r
256         configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );\r
257         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
258         ( void ) ulNotifiedValue;\r
259 \r
260         /* Should not be any notifications pending now. */\r
261         xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );\r
262         configASSERT( xReturned == pdFAIL );\r
263         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
264         ( void ) ulNotifiedValue;\r
265 \r
266 \r
267 \r
268 \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
275         ulLoop = 0;\r
276 \r
277         /* Start with all bits clear. */\r
278         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
279 \r
280         do\r
281         {\r
282                 /* Set the next bit in the task's notified value. */\r
283                 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );\r
284 \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
290                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
291 \r
292                 ulLoop++;\r
293 \r
294                 /* Use the next bit on the next iteration around this loop. */\r
295                 ulNotifyingValue <<= 1UL;\r
296 \r
297         } while ( ulNotifiedValue != notifyUINT32_MAX );\r
298 \r
299         /* As a 32-bit value was used the loop should have executed 32 times before\r
300         all the bits were set. */\r
301         configASSERT( ulLoop == 32 );\r
302 \r
303 \r
304 \r
305 \r
306         /*-------------------------------------------------------------------------\r
307         Check bits are cleared on entry but not on exit when a notification fails\r
308         to arrive before timing out - both with and without a timeout value.  Wait\r
309         for the notification again - but this time it is not given by anything and\r
310         should return pdFAIL.  The parameters are set to clear bit zero on entry and\r
311         bit one on exit.  As no notification was received only the bit cleared on\r
312         entry should actually get cleared. */\r
313         xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );\r
314         configASSERT( xReturned == pdFAIL );\r
315         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
316 \r
317         /* Notify the task with no action so as not to update the bits even though\r
318         notifyUINT32_MAX is used as the notification value. */\r
319         xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );\r
320 \r
321         /* Reading back the value should should find bit 0 is clear, as this was\r
322         cleared on entry, but bit 1 is not clear as it will not have been cleared on\r
323         exit as no notification was received. */\r
324         xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );\r
325         configASSERT( xReturned == pdPASS );\r
326         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );\r
327         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
328 \r
329 \r
330 \r
331 \r
332 \r
333         /*-------------------------------------------------------------------------\r
334         Now try clearing the bit on exit.  For that to happen a notification must be\r
335         received, so the task is notified first. */\r
336         xTaskNotify( xTaskToNotify, 0, eNoAction );\r
337         xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );\r
338 \r
339         /* However as the bit is cleared on exit, after the returned notification\r
340         value is set, the returned notification value should not have the bit\r
341         cleared... */\r
342         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );\r
343 \r
344         /* ...but reading the value back again should find that the bit was indeed\r
345         cleared internally.  The returned value should be pdFAIL however as nothing\r
346         has notified the task in the mean time. */\r
347         xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );\r
348         configASSERT( xReturned == pdFAIL );\r
349         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );\r
350         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
351 \r
352 \r
353 \r
354 \r
355         /*-------------------------------------------------------------------------\r
356         Now try querying the previous value while notifying a task. */\r
357         xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );\r
358         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );\r
359 \r
360         /* Clear all bits. */\r
361         xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );\r
362         xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );\r
363         configASSERT( ulPreviousValue == 0 );\r
364 \r
365         ulExpectedValue = 0;\r
366         for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )\r
367         {\r
368                 /* Set the next bit up, and expect to receive the last bits set (so\r
369                 the previous value will not yet have the bit being set this time\r
370                 around). */\r
371                 xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );\r
372                 configASSERT( ulExpectedValue == ulPreviousValue );\r
373                 ulExpectedValue |= ulLoop;\r
374         }\r
375 \r
376 \r
377 \r
378         /* ------------------------------------------------------------------------\r
379         Clear the previous notifications. */\r
380         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
381 \r
382         /* The task should not have any notifications pending, so an attempt to clear\r
383         the notification state should fail. */\r
384         configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );\r
385 \r
386         /* Get the task to notify itself.  This is not a normal thing to do, and is\r
387         only done here for test purposes. */\r
388         xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );\r
389 \r
390         /* Now the notification state should be eNotified, so it should now be\r
391         possible to clear the notification state. */\r
392         configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );\r
393         configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );\r
394 \r
395 \r
396 \r
397         /* ------------------------------------------------------------------------\r
398         Create a timer that will try notifying this task while it is suspended. */\r
399         xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );\r
400         configASSERT( xSingleTaskTimer );\r
401 \r
402         /* Incremented to show the task is still running. */\r
403         ulNotifyCycleCount++;\r
404 \r
405         /* Ensure no notifications are pending. */\r
406         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
407 \r
408         /* Raise the task's priority so it can suspend itself before the timer\r
409         expires. */\r
410         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
411 \r
412         /* Start the timer that will try notifying this task while it is\r
413         suspended, then wait for a notification.  The first time the callback\r
414         executes the timer will suspend the task, then resume the task, without\r
415         ever sending a notification to the task. */\r
416         ulNotifiedValue = 0;\r
417         xTimerStart( xSingleTaskTimer, portMAX_DELAY );\r
418 \r
419         /* Check a notification is not received. */\r
420         xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );\r
421         configASSERT( xReturned == pdFALSE );\r
422         configASSERT( ulNotifiedValue == 0 );\r
423         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
424 \r
425         /* Incremented to show the task is still running. */\r
426         ulNotifyCycleCount++;\r
427 \r
428         /* Start the timer that will try notifying this task while it is\r
429         suspended, then wait for a notification.  The second time the callback\r
430         executes the timer will suspend the task, notify the task, then resume the\r
431         task (previously it was suspended and resumed without being notified). */\r
432         xTimerStart( xSingleTaskTimer, portMAX_DELAY );\r
433 \r
434         /* Check a notification is received. */\r
435         xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );\r
436         configASSERT( xReturned == pdPASS );\r
437         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
438         configASSERT( ulNotifiedValue != 0 );\r
439 \r
440         /* Return the task to its proper priority and delete the timer as it is\r
441         not used again. */\r
442         vTaskPrioritySet( NULL, notifyTASK_PRIORITY );\r
443         xTimerDelete( xSingleTaskTimer, portMAX_DELAY );\r
444 \r
445         /* Incremented to show the task is still running. */\r
446         ulNotifyCycleCount++;\r
447 \r
448         /* Leave all bits cleared. */\r
449         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
450 }\r
451 /*-----------------------------------------------------------*/\r
452 \r
453 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )\r
454 {\r
455 static uint32_t ulCallCount = 0;\r
456 \r
457         /* Remove compiler warnings about unused parameters. */\r
458         ( void ) xExpiredTimer;\r
459 \r
460         /* Callback for a timer that is used during preliminary testing.  The timer\r
461         tests the behaviour when 1: a task waiting for a notification is suspended\r
462         and then resumed without ever receiving a notification, and 2: when a task\r
463         waiting for a notification receives a notification while it is suspended. */\r
464 \r
465         if( ulCallCount == 0 )\r
466         {\r
467                 vTaskSuspend( xTaskToNotify );\r
468                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
469                 vTaskResume( xTaskToNotify );\r
470         }\r
471         else\r
472         {\r
473                 vTaskSuspend( xTaskToNotify );\r
474 \r
475                 /* Sending a notification while the task is suspended should pass, but\r
476                 not cause the task to resume.  ulCallCount is just used as a convenient\r
477                 non-zero value. */\r
478                 xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );\r
479 \r
480                 /* Make sure giving the notification didn't resume the task. */\r
481                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
482 \r
483                 vTaskResume( xTaskToNotify );\r
484         }\r
485 \r
486         ulCallCount++;\r
487 }\r
488 /*-----------------------------------------------------------*/\r
489 \r
490 static void prvNotifyingTimer( TimerHandle_t xNotUsed )\r
491 {\r
492         ( void ) xNotUsed;\r
493 \r
494         xTaskNotifyGive( xTaskToNotify );\r
495 \r
496         /* This value is also incremented from an interrupt. */\r
497         taskENTER_CRITICAL();\r
498         {\r
499                 ulTimerNotificationsSent++;\r
500         }\r
501         taskEXIT_CRITICAL();\r
502 }\r
503 /*-----------------------------------------------------------*/\r
504 \r
505 static void prvNotifiedTask( void *pvParameters )\r
506 {\r
507 const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;\r
508 TickType_t xPeriod;\r
509 const uint32_t ulCyclesToRaisePriority = 50UL;\r
510 \r
511         /* Remove compiler warnings about unused parameters. */\r
512         ( void ) pvParameters;\r
513 \r
514         /* Run a few tests that can be done from a single task before entering the\r
515         main loop. */\r
516         prvSingleTaskTests();\r
517 \r
518         /* Create the software timer that is used to send notifications to this\r
519         task.  Notifications are also received from an interrupt. */\r
520         xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );\r
521 \r
522         for( ;; )\r
523         {\r
524                 /* Start the timer again with a different period.  Sometimes the period\r
525                 will be higher than the task's block time, sometimes it will be lower\r
526                 than the task's block time. */\r
527                 xPeriod = prvRand() % xMaxPeriod;\r
528                 if( xPeriod < xMinPeriod )\r
529                 {\r
530                         xPeriod = xMinPeriod;\r
531                 }\r
532 \r
533                 /* Change the timer period and start the timer. */\r
534                 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );\r
535 \r
536                 /* Block waiting for the notification again with a different period.\r
537                 Sometimes the period will be higher than the task's block time,\r
538                 sometimes it will be lower than the task's block time. */\r
539                 xPeriod = prvRand() % xMaxPeriod;\r
540                 if( xPeriod < xMinPeriod )\r
541                 {\r
542                         xPeriod = xMinPeriod;\r
543                 }\r
544 \r
545                 /* Block to wait for a notification but without clearing the\r
546                 notification count, so only add one to the count of received\r
547                 notifications as any other notifications will remain pending. */\r
548                 if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )\r
549                 {\r
550                         ulTimerNotificationsReceived++;\r
551                 }\r
552 \r
553 \r
554                 /* Take a notification without clearing again, but this time without a\r
555                 block time specified. */\r
556                 if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )\r
557                 {\r
558                         ulTimerNotificationsReceived++;\r
559                 }\r
560 \r
561                 /* Wait for the next notification from the timer, clearing all\r
562                 notifications if one is received, so this time adding the total number\r
563                 of notifications that were pending as none will be left pending after\r
564                 the function call. */\r
565                 ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );\r
566 \r
567                 /* Occasionally raise the priority of the task being notified to test\r
568                 the path where the task is notified from an ISR and becomes the highest\r
569                 priority ready state task, but the pxHigherPriorityTaskWoken parameter\r
570                 is NULL (which it is in the tick hook that sends notifications to this\r
571                 task). */\r
572                 if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )\r
573                 {\r
574                         vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );\r
575 \r
576                         /* Wait for the next notification again, clearing all notifications\r
577                         if one is received, but this time blocking indefinitely. */\r
578                         ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );\r
579 \r
580                         /* Reset the priority. */\r
581                         vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );\r
582                 }\r
583                 else\r
584                 {\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
588                 }\r
589 \r
590                 /* Incremented to show the task is still running. */\r
591                 ulNotifyCycleCount++;\r
592         }\r
593 }\r
594 /*-----------------------------------------------------------*/\r
595 \r
596 void xNotifyTaskFromISR( void )\r
597 {\r
598 static BaseType_t xCallCount = 0, xAPIToUse = 0;\r
599 const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );\r
600 uint32_t ulPreviousValue;\r
601 const uint32_t ulUnexpectedValue = 0xff;\r
602 \r
603         /* The task performs some tests before starting the timer that gives the\r
604         notification from this interrupt.  If the timer has not been created yet\r
605         then the initial tests have not yet completed and the notification should\r
606         not be sent. */\r
607         if( xTimer != NULL )\r
608         {\r
609                 xCallCount++;\r
610 \r
611                 if( xCallCount >= xCallInterval )\r
612                 {\r
613                         /* It is time to 'give' the notification again. */\r
614                         xCallCount = 0;\r
615 \r
616                         /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()\r
617                         and xTaskNotifyAndQueryFromISR(). */\r
618                         switch( xAPIToUse )\r
619                         {\r
620                                 case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );\r
621                                                 xAPIToUse++;\r
622                                                 break;\r
623 \r
624                                 case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );\r
625                                                 xAPIToUse++;\r
626                                                 break;\r
627 \r
628                                 case 2: ulPreviousValue = ulUnexpectedValue;\r
629                                                 xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );\r
630                                                 configASSERT( ulPreviousValue != ulUnexpectedValue );\r
631                                                 xAPIToUse = 0;\r
632                                                 break;\r
633 \r
634                                 default:/* Should never get here!. */\r
635                                                 break;\r
636                         }\r
637 \r
638                         ulTimerNotificationsSent++;\r
639                 }\r
640         }\r
641 }\r
642 /*-----------------------------------------------------------*/\r
643 \r
644 /* This is called to check the created tasks are still running and have not\r
645 detected any errors. */\r
646 BaseType_t xAreTaskNotificationTasksStillRunning( void )\r
647 {\r
648 static uint32_t ulLastNotifyCycleCount = 0;\r
649 const uint32_t ulMaxSendReceiveDeviation = 5UL;\r
650 \r
651         /* Check the cycle count is still incrementing to ensure the task is still\r
652         actually running. */\r
653         if( ulLastNotifyCycleCount == ulNotifyCycleCount )\r
654         {\r
655                 xErrorStatus = pdFAIL;\r
656         }\r
657         else\r
658         {\r
659                 ulLastNotifyCycleCount = ulNotifyCycleCount;\r
660         }\r
661 \r
662         /* Check the count of 'takes' from the software timer is keeping track with\r
663         the amount of 'gives'. */\r
664         if( ulTimerNotificationsSent > ulTimerNotificationsReceived )\r
665         {\r
666                 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )\r
667                 {\r
668                         xErrorStatus = pdFAIL;\r
669                 }\r
670         }\r
671 \r
672         return xErrorStatus;\r
673 }\r
674 /*-----------------------------------------------------------*/\r
675 \r
676 static UBaseType_t prvRand( void )\r
677 {\r
678 const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;\r
679 \r
680         /* Utility function to generate a pseudo random number. */\r
681         uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;\r
682         return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );\r
683 }\r
684 /*-----------------------------------------------------------*/\r