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