]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/TaskNotify.c
Added xTaskAbortDelayFromISR() and ulTaskNotifyValueClear() API functions.
[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 \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
55 \r
56 #define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )\r
57 \r
58 /*-----------------------------------------------------------*/\r
59 \r
60 /*\r
61  * Implementation of the task that gets notified.\r
62  */\r
63 static void prvNotifiedTask( void *pvParameters );\r
64 \r
65 /*\r
66  * Performs a few initial tests that can be done prior to creating the second\r
67  * task.\r
68  */\r
69 static void prvSingleTaskTests( void );\r
70 \r
71 /*\r
72  * Software timer callback function from which xTaskNotify() is called.\r
73  */\r
74 static void prvNotifyingTimer( TimerHandle_t xTimer );\r
75 \r
76 /*\r
77  * Utility function to create pseudo random numbers.\r
78  */\r
79 static UBaseType_t prvRand( void );\r
80 \r
81 /*\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
86  */\r
87 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );\r
88 \r
89 /*-----------------------------------------------------------*/\r
90 \r
91 /* Used to latch errors during the test's execution. */\r
92 static BaseType_t xErrorStatus = pdPASS;\r
93 \r
94 /* Used to ensure the task has not stalled. */\r
95 static volatile uint32_t ulNotifyCycleCount = 0;\r
96 \r
97 /* The handle of the task that receives the notifications. */\r
98 static TaskHandle_t xTaskToNotify = NULL;\r
99 \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
104 \r
105 /* The timer used to notify the task. */\r
106 static TimerHandle_t xTimer = NULL;\r
107 \r
108 /* Used by the pseudo random number generating function. */\r
109 static size_t uxNextRand = 0;\r
110 \r
111 /*-----------------------------------------------------------*/\r
112 \r
113 void vStartTaskNotifyTask( void  )\r
114 {\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
123 \r
124         /* Pseudo seed the random number generator. */\r
125         uxNextRand = ( size_t ) prvRand;\r
126 }\r
127 /*-----------------------------------------------------------*/\r
128 \r
129 static void prvSingleTaskTests( void )\r
130 {\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
138 \r
139 \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
145 \r
146         /* Should have blocked for the entire block time. */\r
147         if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )\r
148         {\r
149                 xErrorStatus = pdFAIL;\r
150         }\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
155 \r
156 \r
157 \r
158 \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
162         only. */\r
163         xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );\r
164 \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
169 \r
170         /* No bits should have been pending previously. */\r
171         configASSERT( ulPreviousValue == 0 );\r
172         ( void ) ulPreviousValue;\r
173 \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
177 \r
178         if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )\r
179         {\r
180                 xErrorStatus = pdFAIL;\r
181         }\r
182 \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
189 \r
190         /* Incremented to show the task is still running. */\r
191         ulNotifyCycleCount++;\r
192 \r
193 \r
194 \r
195 \r
196 \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
205 \r
206         xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );\r
207         configASSERT( xReturned == pdFAIL );\r
208         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
209 \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
213 \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
218 \r
219 \r
220 \r
221 \r
222 \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
227         back. */\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
239 \r
240 \r
241 \r
242 \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
253 \r
254 \r
255 \r
256 \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
262         {\r
263                 xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );\r
264                 configASSERT( xReturned == pdPASS );\r
265                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
266         }\r
267 \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
273 \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
279 \r
280 \r
281 \r
282 \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
289         ulLoop = 0;\r
290 \r
291         /* Start with all bits clear. */\r
292         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
293 \r
294         do\r
295         {\r
296                 /* Set the next bit in the task's notified value. */\r
297                 xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );\r
298 \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
305 \r
306                 ulLoop++;\r
307 \r
308                 /* Use the next bit on the next iteration around this loop. */\r
309                 ulNotifyingValue <<= 1UL;\r
310 \r
311         } while ( ulNotifiedValue != notifyUINT32_MAX );\r
312 \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
316 \r
317 \r
318 \r
319 \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
330 \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
334 \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
342 \r
343 \r
344 \r
345 \r
346 \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
352 \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
355         cleared... */\r
356         configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );\r
357 \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
365 \r
366 \r
367 \r
368 \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
373 \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
378 \r
379         ulExpectedValue = 0;\r
380         for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )\r
381         {\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
384                 around). */\r
385                 xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );\r
386                 configASSERT( ulExpectedValue == ulPreviousValue );\r
387                 ulExpectedValue |= ulLoop;\r
388         }\r
389 \r
390 \r
391 \r
392         /* ------------------------------------------------------------------------\r
393         Clear the previous notifications. */\r
394         xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );\r
395 \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
399 \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
403 \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
408 \r
409 \r
410 \r
411         /* ------------------------------------------------------------------------\r
412         Clear bits in the notification value. */\r
413 \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
417 \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
421 \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
425 \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
429 \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
434 \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
439 \r
440 \r
441 \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
446 \r
447         /* Incremented to show the task is still running. */\r
448         ulNotifyCycleCount++;\r
449 \r
450         /* Ensure no notifications are pending. */\r
451         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
452 \r
453         /* Raise the task's priority so it can suspend itself before the timer\r
454         expires. */\r
455         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
456 \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
463 \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
469 \r
470         /* Incremented to show the task is still running. */\r
471         ulNotifyCycleCount++;\r
472 \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
478 \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
484 \r
485         /* Return the task to its proper priority and delete the timer as it is\r
486         not used again. */\r
487         vTaskPrioritySet( NULL, notifyTASK_PRIORITY );\r
488         xTimerDelete( xSingleTaskTimer, portMAX_DELAY );\r
489 \r
490         /* Incremented to show the task is still running. */\r
491         ulNotifyCycleCount++;\r
492 \r
493         /* Leave all bits cleared. */\r
494         xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );\r
495 }\r
496 /*-----------------------------------------------------------*/\r
497 \r
498 static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )\r
499 {\r
500 static uint32_t ulCallCount = 0;\r
501 \r
502         /* Remove compiler warnings about unused parameters. */\r
503         ( void ) xExpiredTimer;\r
504 \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
509 \r
510         if( ulCallCount == 0 )\r
511         {\r
512                 vTaskSuspend( xTaskToNotify );\r
513                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
514                 vTaskResume( xTaskToNotify );\r
515         }\r
516         else\r
517         {\r
518                 vTaskSuspend( xTaskToNotify );\r
519 \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
522                 non-zero value. */\r
523                 xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );\r
524 \r
525                 /* Make sure giving the notification didn't resume the task. */\r
526                 configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );\r
527 \r
528                 vTaskResume( xTaskToNotify );\r
529         }\r
530 \r
531         ulCallCount++;\r
532 }\r
533 /*-----------------------------------------------------------*/\r
534 \r
535 static void prvNotifyingTimer( TimerHandle_t xNotUsed )\r
536 {\r
537         ( void ) xNotUsed;\r
538 \r
539         xTaskNotifyGive( xTaskToNotify );\r
540 \r
541         /* This value is also incremented from an interrupt. */\r
542         taskENTER_CRITICAL();\r
543         {\r
544                 ulTimerNotificationsSent++;\r
545         }\r
546         taskEXIT_CRITICAL();\r
547 }\r
548 /*-----------------------------------------------------------*/\r
549 \r
550 static void prvNotifiedTask( void *pvParameters )\r
551 {\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
555 \r
556         /* Remove compiler warnings about unused parameters. */\r
557         ( void ) pvParameters;\r
558 \r
559         /* Run a few tests that can be done from a single task before entering the\r
560         main loop. */\r
561         prvSingleTaskTests();\r
562 \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
566 \r
567         for( ;; )\r
568         {\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
574                 {\r
575                         xPeriod = xMinPeriod;\r
576                 }\r
577 \r
578                 /* Change the timer period and start the timer. */\r
579                 xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );\r
580 \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
586                 {\r
587                         xPeriod = xMinPeriod;\r
588                 }\r
589 \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
594                 {\r
595                         ulTimerNotificationsReceived++;\r
596                 }\r
597 \r
598 \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
602                 {\r
603                         ulTimerNotificationsReceived++;\r
604                 }\r
605 \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
611 \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
616                 task). */\r
617                 if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )\r
618                 {\r
619                         vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );\r
620 \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
624 \r
625                         /* Reset the priority. */\r
626                         vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );\r
627                 }\r
628                 else\r
629                 {\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
633                 }\r
634 \r
635                 /* Incremented to show the task is still running. */\r
636                 ulNotifyCycleCount++;\r
637         }\r
638 }\r
639 /*-----------------------------------------------------------*/\r
640 \r
641 void xNotifyTaskFromISR( void )\r
642 {\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
647 \r
648         /* Check the task notification demo tasks were actually created. */\r
649         configASSERT( xTaskToNotify );\r
650 \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
654         not be sent. */\r
655         if( xTimer != NULL )\r
656         {\r
657                 xCallCount++;\r
658 \r
659                 if( xCallCount >= xCallInterval )\r
660                 {\r
661                         /* It is time to 'give' the notification again. */\r
662                         xCallCount = 0;\r
663 \r
664                         /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()\r
665                         and xTaskNotifyAndQueryFromISR(). */\r
666                         switch( xAPIToUse )\r
667                         {\r
668                                 case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );\r
669                                                 xAPIToUse++;\r
670                                                 break;\r
671 \r
672                                 case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );\r
673                                                 xAPIToUse++;\r
674                                                 break;\r
675 \r
676                                 case 2: ulPreviousValue = ulUnexpectedValue;\r
677                                                 xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );\r
678                                                 configASSERT( ulPreviousValue != ulUnexpectedValue );\r
679                                                 xAPIToUse = 0;\r
680                                                 break;\r
681 \r
682                                 default:/* Should never get here!. */\r
683                                                 break;\r
684                         }\r
685 \r
686                         ulTimerNotificationsSent++;\r
687                 }\r
688         }\r
689 }\r
690 /*-----------------------------------------------------------*/\r
691 \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
695 {\r
696 static uint32_t ulLastNotifyCycleCount = 0;\r
697 const uint32_t ulMaxSendReceiveDeviation = 5UL;\r
698 \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
702         {\r
703                 xErrorStatus = pdFAIL;\r
704         }\r
705         else\r
706         {\r
707                 ulLastNotifyCycleCount = ulNotifyCycleCount;\r
708         }\r
709 \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
713         {\r
714                 if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )\r
715                 {\r
716                         xErrorStatus = pdFAIL;\r
717                 }\r
718         }\r
719 \r
720         return xErrorStatus;\r
721 }\r
722 /*-----------------------------------------------------------*/\r
723 \r
724 static UBaseType_t prvRand( void )\r
725 {\r
726 const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;\r
727 \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
731 }\r
732 /*-----------------------------------------------------------*/\r