]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/TaskNotify.c
4adc06f56d6af4b7312c55b3d79cfeabc6c2b682
[freertos] / FreeRTOS / Demo / Common / Minimal / TaskNotify.c
1 /*\r
2  * FreeRTOS Kernel V10.2.1\r
3  * Copyright (C) 2019 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.\r
14  *\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
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 /*\r
30  * Tests the behaviour of direct task notifications.\r
31  */\r
32 \r
33 /* Standard includes. */\r
34 #include <limits.h>\r
35 \r
36 /* Scheduler include files. */\r
37 #include "FreeRTOS.h"\r
38 #include "task.h"\r
39 #include "timers.h"\r
40 \r
41 /* Demo program include files. */\r
42 #include "TaskNotify.h"\r
43 \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
47 #endif\r
48 \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
52 \r
53 /*-----------------------------------------------------------*/\r
54 \r
55 /*\r
56  * Implementation of the task that gets notified.\r
57  */\r
58 static void prvNotifiedTask( void *pvParameters );\r
59 \r
60 /*\r
61  * Performs a few initial tests that can be done prior to creating the second\r
62  * task.\r
63  */\r
64 static void prvSingleTaskTests( void );\r
65 \r
66 /*\r
67  * Software timer callback function from which xTaskNotify() is called.\r
68  */\r
69 static void prvNotifyingTimer( TimerHandle_t xTimer );\r
70 \r
71 /*\r
72  * Utility function to create pseudo random numbers.\r
73  */\r
74 static UBaseType_t prvRand( void );\r
75 \r
76 /*\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
81  */\r
82 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );\r
83 \r
84 /*-----------------------------------------------------------*/\r
85 \r
86 /* Used to latch errors during the test's execution. */\r
87 static BaseType_t xErrorStatus = pdPASS;\r
88 \r
89 /* Used to ensure the task has not stalled. */\r
90 static volatile uint32_t ulNotifyCycleCount = 0;\r
91 \r
92 /* The handle of the task that receives the notifications. */\r
93 static TaskHandle_t xTaskToNotify = NULL;\r
94 \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
99 \r
100 /* The timer used to notify the task. */\r
101 static TimerHandle_t xTimer = NULL;\r
102 \r
103 /* Used by the pseudo random number generating function. */\r
104 static size_t uxNextRand = 0;\r
105 \r
106 /*-----------------------------------------------------------*/\r
107 \r
108 void vStartTaskNotifyTask( void  )\r
109 {\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
118 \r
119         /* Pseudo seed the random number generator. */\r
120         uxNextRand = ( size_t ) prvRand;\r
121 }\r
122 /*-----------------------------------------------------------*/\r
123 \r
124 static void prvSingleTaskTests( void )\r
125 {\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
133 \r
134 \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
140 \r
141         /* Should have blocked for the entire block time. */\r
142         if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )\r
143         {\r
144                 xErrorStatus = pdFAIL;\r
145         }\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
150 \r
151 \r
152 \r
153 \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
157         only. */\r
158         xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );\r
159 \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
164 \r
165         /* No bits should have been pending previously. */\r
166         configASSERT( ulPreviousValue == 0 );\r
167         ( void ) ulPreviousValue;\r
168 \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
172 \r
173         if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )\r
174         {\r
175                 xErrorStatus = pdFAIL;\r
176         }\r
177 \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
184 \r
185         /* Incremented to show the task is still running. */\r
186         ulNotifyCycleCount++;\r
187 \r
188 \r
189 \r
190 \r
191 \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
200 \r
201         xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );\r
202         configASSERT( xReturned == pdFAIL );\r
203         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
204 \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
208 \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
213 \r
214 \r
215 \r
216 \r
217 \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
222         back. */\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
234 \r
235 \r
236 \r
237 \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
248 \r
249 \r
250 \r
251 \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
257         {\r
258                 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );\r
259                 configASSERT( xReturned == pdPASS );\r
260                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
261         }\r
262 \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
268 \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
274 \r
275 \r
276 \r
277 \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
284         ulLoop = 0;\r
285 \r
286         /* Start with all bits clear. */\r
287         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
288 \r
289         do\r
290         {\r
291                 /* Set the next bit in the task's notified value. */\r
292                 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );\r
293 \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
300 \r
301                 ulLoop++;\r
302 \r
303                 /* Use the next bit on the next iteration around this loop. */\r
304                 ulNotifyingValue <<= 1UL;\r
305 \r
306         } while ( ulNotifiedValue != notifyUINT32_MAX );\r
307 \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
311 \r
312 \r
313 \r
314 \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
325 \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
329 \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
337 \r
338 \r
339 \r
340 \r
341 \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
347 \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
350         cleared... */\r
351         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );\r
352 \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
360 \r
361 \r
362 \r
363 \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
368 \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
373 \r
374         ulExpectedValue = 0;\r
375         for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )\r
376         {\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
379                 around). */\r
380                 xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );\r
381                 configASSERT( ulExpectedValue == ulPreviousValue );\r
382                 ulExpectedValue |= ulLoop;\r
383         }\r
384 \r
385 \r
386 \r
387         /* ------------------------------------------------------------------------\r
388         Clear the previous notifications. */\r
389         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
390 \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
394 \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
398 \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
403 \r
404 \r
405 \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
410 \r
411         /* Incremented to show the task is still running. */\r
412         ulNotifyCycleCount++;\r
413 \r
414         /* Ensure no notifications are pending. */\r
415         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
416 \r
417         /* Raise the task's priority so it can suspend itself before the timer\r
418         expires. */\r
419         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
420 \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
427 \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
433 \r
434         /* Incremented to show the task is still running. */\r
435         ulNotifyCycleCount++;\r
436 \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
442 \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
448 \r
449         /* Return the task to its proper priority and delete the timer as it is\r
450         not used again. */\r
451         vTaskPrioritySet( NULL, notifyTASK_PRIORITY );\r
452         xTimerDelete( xSingleTaskTimer, portMAX_DELAY );\r
453 \r
454         /* Incremented to show the task is still running. */\r
455         ulNotifyCycleCount++;\r
456 \r
457         /* Leave all bits cleared. */\r
458         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
459 }\r
460 /*-----------------------------------------------------------*/\r
461 \r
462 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )\r
463 {\r
464 static uint32_t ulCallCount = 0;\r
465 \r
466         /* Remove compiler warnings about unused parameters. */\r
467         ( void ) xExpiredTimer;\r
468 \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
473 \r
474         if( ulCallCount == 0 )\r
475         {\r
476                 vTaskSuspend( xTaskToNotify );\r
477                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
478                 vTaskResume( xTaskToNotify );\r
479         }\r
480         else\r
481         {\r
482                 vTaskSuspend( xTaskToNotify );\r
483 \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
486                 non-zero value. */\r
487                 xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );\r
488 \r
489                 /* Make sure giving the notification didn't resume the task. */\r
490                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
491 \r
492                 vTaskResume( xTaskToNotify );\r
493         }\r
494 \r
495         ulCallCount++;\r
496 }\r
497 /*-----------------------------------------------------------*/\r
498 \r
499 static void prvNotifyingTimer( TimerHandle_t xNotUsed )\r
500 {\r
501         ( void ) xNotUsed;\r
502 \r
503         xTaskNotifyGive( xTaskToNotify );\r
504 \r
505         /* This value is also incremented from an interrupt. */\r
506         taskENTER_CRITICAL();\r
507         {\r
508                 ulTimerNotificationsSent++;\r
509         }\r
510         taskEXIT_CRITICAL();\r
511 }\r
512 /*-----------------------------------------------------------*/\r
513 \r
514 static void prvNotifiedTask( void *pvParameters )\r
515 {\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
519 \r
520         /* Remove compiler warnings about unused parameters. */\r
521         ( void ) pvParameters;\r
522 \r
523         /* Run a few tests that can be done from a single task before entering the\r
524         main loop. */\r
525         prvSingleTaskTests();\r
526 \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
530 \r
531         for( ;; )\r
532         {\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
538                 {\r
539                         xPeriod = xMinPeriod;\r
540                 }\r
541 \r
542                 /* Change the timer period and start the timer. */\r
543                 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );\r
544 \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
550                 {\r
551                         xPeriod = xMinPeriod;\r
552                 }\r
553 \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
558                 {\r
559                         ulTimerNotificationsReceived++;\r
560                 }\r
561 \r
562 \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
566                 {\r
567                         ulTimerNotificationsReceived++;\r
568                 }\r
569 \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
575 \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
580                 task). */\r
581                 if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )\r
582                 {\r
583                         vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );\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                         /* Reset the priority. */\r
590                         vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );\r
591                 }\r
592                 else\r
593                 {\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
597                 }\r
598 \r
599                 /* Incremented to show the task is still running. */\r
600                 ulNotifyCycleCount++;\r
601         }\r
602 }\r
603 /*-----------------------------------------------------------*/\r
604 \r
605 void xNotifyTaskFromISR( void )\r
606 {\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
611 \r
612         /* Check the task notification demo tasks were actually created. */\r
613         configASSERT( xTaskToNotify );\r
614 \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
618         not be sent. */\r
619         if( xTimer != NULL )\r
620         {\r
621                 xCallCount++;\r
622 \r
623                 if( xCallCount >= xCallInterval )\r
624                 {\r
625                         /* It is time to 'give' the notification again. */\r
626                         xCallCount = 0;\r
627 \r
628                         /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()\r
629                         and xTaskNotifyAndQueryFromISR(). */\r
630                         switch( xAPIToUse )\r
631                         {\r
632                                 case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );\r
633                                                 xAPIToUse++;\r
634                                                 break;\r
635 \r
636                                 case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );\r
637                                                 xAPIToUse++;\r
638                                                 break;\r
639 \r
640                                 case 2: ulPreviousValue = ulUnexpectedValue;\r
641                                                 xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );\r
642                                                 configASSERT( ulPreviousValue != ulUnexpectedValue );\r
643                                                 xAPIToUse = 0;\r
644                                                 break;\r
645 \r
646                                 default:/* Should never get here!. */\r
647                                                 break;\r
648                         }\r
649 \r
650                         ulTimerNotificationsSent++;\r
651                 }\r
652         }\r
653 }\r
654 /*-----------------------------------------------------------*/\r
655 \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
659 {\r
660 static uint32_t ulLastNotifyCycleCount = 0;\r
661 const uint32_t ulMaxSendReceiveDeviation = 5UL;\r
662 \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
666         {\r
667                 xErrorStatus = pdFAIL;\r
668         }\r
669         else\r
670         {\r
671                 ulLastNotifyCycleCount = ulNotifyCycleCount;\r
672         }\r
673 \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
677         {\r
678                 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )\r
679                 {\r
680                         xErrorStatus = pdFAIL;\r
681                 }\r
682         }\r
683 \r
684         return xErrorStatus;\r
685 }\r
686 /*-----------------------------------------------------------*/\r
687 \r
688 static UBaseType_t prvRand( void )\r
689 {\r
690 const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;\r
691 \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
695 }\r
696 /*-----------------------------------------------------------*/\r