]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RL78_E2Studio_GCC/src/Common-Demo-Tasks/blocktim.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / RL78_E2Studio_GCC / src / Common-Demo-Tasks / blocktim.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /*\r
30  * This file contains some test scenarios that ensure tasks do not exit queue\r
31  * send or receive functions prematurely.  A description of the tests is\r
32  * included within the code.\r
33  */\r
34 \r
35 /* Kernel includes. */\r
36 #include "FreeRTOS.h"\r
37 #include "task.h"\r
38 #include "queue.h"\r
39 \r
40 /* Demo includes. */\r
41 #include "blocktim.h"\r
42 \r
43 /* Task priorities.  Allow these to be overridden. */\r
44 #ifndef bktPRIMARY_PRIORITY\r
45         #define bktPRIMARY_PRIORITY             ( configMAX_PRIORITIES - 3 )\r
46 #endif\r
47 \r
48 #ifndef bktSECONDARY_PRIORITY\r
49         #define bktSECONDARY_PRIORITY   ( configMAX_PRIORITIES - 4 )\r
50 #endif\r
51 \r
52 /* Task behaviour. */\r
53 #define bktQUEUE_LENGTH                         ( 5 )\r
54 #define bktSHORT_WAIT                           ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )\r
55 #define bktPRIMARY_BLOCK_TIME           ( 10 )\r
56 #define bktALLOWABLE_MARGIN                     ( 15 )\r
57 #define bktTIME_TO_BLOCK                        ( 175 )\r
58 #define bktDONT_BLOCK                           ( ( TickType_t ) 0 )\r
59 #define bktRUN_INDICATOR                        ( ( unsigned portBASE_TYPE ) 0x55 )\r
60 \r
61 /* The queue on which the tasks block. */\r
62 static QueueHandle_t xTestQueue;\r
63 \r
64 /* Handle to the secondary task is required by the primary task for calls\r
65 to vTaskSuspend/Resume(). */\r
66 static TaskHandle_t xSecondary;\r
67 \r
68 /* Used to ensure that tasks are still executing without error. */\r
69 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;\r
70 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;\r
71 \r
72 /* Provides a simple mechanism for the primary task to know when the\r
73 secondary task has executed. */\r
74 static volatile unsigned portBASE_TYPE xRunIndicator;\r
75 \r
76 /* The two test tasks.  Their behaviour is commented within the files. */\r
77 static void vPrimaryBlockTimeTestTask( void *pvParameters );\r
78 static void vSecondaryBlockTimeTestTask( void *pvParameters );\r
79 \r
80 /*-----------------------------------------------------------*/\r
81 \r
82 void vCreateBlockTimeTasks( void )\r
83 {\r
84         /* Create the queue on which the two tasks block. */\r
85     xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );\r
86 \r
87         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
88         in use.  The queue registry is provided as a means for kernel aware\r
89         debuggers to locate queues and has no purpose if a kernel aware debugger\r
90         is not being used.  The call to vQueueAddToRegistry() will be removed\r
91         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
92         defined to be less than 1. */\r
93         vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );\r
94 \r
95         /* Create the two test tasks. */\r
96         xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );\r
97         xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );\r
98 }\r
99 /*-----------------------------------------------------------*/\r
100 \r
101 static void vPrimaryBlockTimeTestTask( void *pvParameters )\r
102 {\r
103 portBASE_TYPE xItem, xData;\r
104 TickType_t xTimeWhenBlocking;\r
105 TickType_t xTimeToBlock, xBlockedTime;\r
106 \r
107         ( void ) pvParameters;\r
108 \r
109         for( ;; )\r
110         {\r
111                 /*********************************************************************\r
112         Test 1\r
113 \r
114         Simple block time wakeup test on queue receives. */\r
115                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
116                 {\r
117                         /* The queue is empty. Attempt to read from the queue using a block\r
118                         time.  When we wake, ensure the delta in time is as expected. */\r
119                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
120 \r
121                         xTimeWhenBlocking = xTaskGetTickCount();\r
122 \r
123                         /* We should unblock after xTimeToBlock having not received\r
124                         anything on the queue. */\r
125                         if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )\r
126                         {\r
127                                 xErrorOccurred = pdTRUE;\r
128                         }\r
129 \r
130                         /* How long were we blocked for? */\r
131                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
132 \r
133                         if( xBlockedTime < xTimeToBlock )\r
134                         {\r
135                                 /* Should not have blocked for less than we requested. */\r
136                                 xErrorOccurred = pdTRUE;\r
137                         }\r
138 \r
139                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
140                         {\r
141                                 /* Should not have blocked for longer than we requested,\r
142                                 although we would not necessarily run as soon as we were\r
143                                 unblocked so a margin is allowed. */\r
144                                 xErrorOccurred = pdTRUE;\r
145                         }\r
146                 }\r
147 \r
148                 /*********************************************************************\r
149         Test 2\r
150 \r
151         Simple block time wakeup test on queue sends.\r
152 \r
153                 First fill the queue.  It should be empty so all sends should pass. */\r
154                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
155                 {\r
156                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
157                         {\r
158                                 xErrorOccurred = pdTRUE;\r
159                         }\r
160 \r
161                         #if configUSE_PREEMPTION == 0\r
162                                 taskYIELD();\r
163                         #endif\r
164                 }\r
165 \r
166                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
167                 {\r
168                         /* The queue is full. Attempt to write to the queue using a block\r
169                         time.  When we wake, ensure the delta in time is as expected. */\r
170                         xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
171 \r
172                         xTimeWhenBlocking = xTaskGetTickCount();\r
173 \r
174                         /* We should unblock after xTimeToBlock having not received\r
175                         anything on the queue. */\r
176                         if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )\r
177                         {\r
178                                 xErrorOccurred = pdTRUE;\r
179                         }\r
180 \r
181                         /* How long were we blocked for? */\r
182                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
183 \r
184                         if( xBlockedTime < xTimeToBlock )\r
185                         {\r
186                                 /* Should not have blocked for less than we requested. */\r
187                                 xErrorOccurred = pdTRUE;\r
188                         }\r
189 \r
190                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
191                         {\r
192                                 /* Should not have blocked for longer than we requested,\r
193                                 although we would not necessarily run as soon as we were\r
194                                 unblocked so a margin is allowed. */\r
195                                 xErrorOccurred = pdTRUE;\r
196                         }\r
197                 }\r
198 \r
199                 /*********************************************************************\r
200         Test 3\r
201 \r
202                 Wake the other task, it will block attempting to post to the queue.\r
203                 When we read from the queue the other task will wake, but before it\r
204                 can run we will post to the queue again.  When the other task runs it\r
205                 will find the queue still full, even though it was woken.  It should\r
206                 recognise that its block time has not expired and return to block for\r
207                 the remains of its block time.\r
208 \r
209                 Wake the other task so it blocks attempting to post to the already\r
210                 full queue. */\r
211                 xRunIndicator = 0;\r
212                 vTaskResume( xSecondary );\r
213 \r
214                 /* We need to wait a little to ensure the other task executes. */\r
215                 while( xRunIndicator != bktRUN_INDICATOR )\r
216                 {\r
217                         /* The other task has not yet executed. */\r
218                         vTaskDelay( bktSHORT_WAIT );\r
219                 }\r
220                 /* Make sure the other task is blocked on the queue. */\r
221                 vTaskDelay( bktSHORT_WAIT );\r
222                 xRunIndicator = 0;\r
223 \r
224                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
225                 {\r
226                         /* Now when we make space on the queue the other task should wake\r
227                         but not execute as this task has higher priority. */\r
228                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
229                         {\r
230                                 xErrorOccurred = pdTRUE;\r
231                         }\r
232 \r
233                         /* Now fill the queue again before the other task gets a chance to\r
234                         execute.  If the other task had executed we would find the queue\r
235                         full ourselves, and the other task have set xRunIndicator. */\r
236                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
237                         {\r
238                                 xErrorOccurred = pdTRUE;\r
239                         }\r
240 \r
241                         if( xRunIndicator == bktRUN_INDICATOR )\r
242                         {\r
243                                 /* The other task should not have executed. */\r
244                                 xErrorOccurred = pdTRUE;\r
245                         }\r
246 \r
247                         /* Raise the priority of the other task so it executes and blocks\r
248                         on the queue again. */\r
249                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
250 \r
251                         /* The other task should now have re-blocked without exiting the\r
252                         queue function. */\r
253                         if( xRunIndicator == bktRUN_INDICATOR )\r
254                         {\r
255                                 /* The other task should not have executed outside of the\r
256                                 queue function. */\r
257                                 xErrorOccurred = pdTRUE;\r
258                         }\r
259 \r
260                         /* Set the priority back down. */\r
261                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
262                 }\r
263 \r
264                 /* Let the other task timeout.  When it unblockes it will check that it\r
265                 unblocked at the correct time, then suspend itself. */\r
266                 while( xRunIndicator != bktRUN_INDICATOR )\r
267                 {\r
268                         vTaskDelay( bktSHORT_WAIT );\r
269                 }\r
270                 vTaskDelay( bktSHORT_WAIT );\r
271                 xRunIndicator = 0;\r
272 \r
273 \r
274                 /*********************************************************************\r
275         Test 4\r
276 \r
277                 As per test 3 - but with the send and receive the other way around.\r
278                 The other task blocks attempting to read from the queue.\r
279 \r
280                 Empty the queue.  We should find that it is full. */\r
281                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
282                 {\r
283                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
284                         {\r
285                                 xErrorOccurred = pdTRUE;\r
286                         }\r
287                 }\r
288 \r
289                 /* Wake the other task so it blocks attempting to read from  the\r
290                 already empty queue. */\r
291                 vTaskResume( xSecondary );\r
292 \r
293                 /* We need to wait a little to ensure the other task executes. */\r
294                 while( xRunIndicator != bktRUN_INDICATOR )\r
295                 {\r
296                         vTaskDelay( bktSHORT_WAIT );\r
297                 }\r
298                 vTaskDelay( bktSHORT_WAIT );\r
299                 xRunIndicator = 0;\r
300 \r
301                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
302                 {\r
303                         /* Now when we place an item on the queue the other task should\r
304                         wake but not execute as this task has higher priority. */\r
305                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
306                         {\r
307                                 xErrorOccurred = pdTRUE;\r
308                         }\r
309 \r
310                         /* Now empty the queue again before the other task gets a chance to\r
311                         execute.  If the other task had executed we would find the queue\r
312                         empty ourselves, and the other task would be suspended. */\r
313                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
314                         {\r
315                                 xErrorOccurred = pdTRUE;\r
316                         }\r
317 \r
318                         if( xRunIndicator == bktRUN_INDICATOR )\r
319                         {\r
320                                 /* The other task should not have executed. */\r
321                                 xErrorOccurred = pdTRUE;\r
322                         }\r
323 \r
324                         /* Raise the priority of the other task so it executes and blocks\r
325                         on the queue again. */\r
326                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
327 \r
328                         /* The other task should now have re-blocked without exiting the\r
329                         queue function. */\r
330                         if( xRunIndicator == bktRUN_INDICATOR )\r
331                         {\r
332                                 /* The other task should not have executed outside of the\r
333                                 queue function. */\r
334                                 xErrorOccurred = pdTRUE;\r
335                         }\r
336                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
337                 }\r
338 \r
339                 /* Let the other task timeout.  When it unblockes it will check that it\r
340                 unblocked at the correct time, then suspend itself. */\r
341                 while( xRunIndicator != bktRUN_INDICATOR )\r
342                 {\r
343                         vTaskDelay( bktSHORT_WAIT );\r
344                 }\r
345                 vTaskDelay( bktSHORT_WAIT );\r
346 \r
347                 xPrimaryCycles++;\r
348         }\r
349 }\r
350 /*-----------------------------------------------------------*/\r
351 \r
352 static void vSecondaryBlockTimeTestTask( void *pvParameters )\r
353 {\r
354 TickType_t xTimeWhenBlocking, xBlockedTime;\r
355 portBASE_TYPE xData;\r
356 \r
357         ( void ) pvParameters;\r
358 \r
359         for( ;; )\r
360         {\r
361                 /*********************************************************************\r
362         Test 1 and 2\r
363 \r
364                 This task does does not participate in these tests. */\r
365                 vTaskSuspend( NULL );\r
366 \r
367                 /*********************************************************************\r
368         Test 3\r
369 \r
370                 The first thing we do is attempt to read from the queue.  It should be\r
371                 full so we block.  Note the time before we block so we can check the\r
372                 wake time is as per that expected. */\r
373                 xTimeWhenBlocking = xTaskGetTickCount();\r
374 \r
375                 /* We should unblock after bktTIME_TO_BLOCK having not sent\r
376                 anything to the queue. */\r
377                 xData = 0;\r
378                 xRunIndicator = bktRUN_INDICATOR;\r
379                 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )\r
380                 {\r
381                         xErrorOccurred = pdTRUE;\r
382                 }\r
383 \r
384                 /* How long were we inside the send function? */\r
385                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
386 \r
387                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
388                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
389                 {\r
390                         xErrorOccurred = pdTRUE;\r
391                 }\r
392 \r
393                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
394                 either.  A margin is permitted as we would not necessarily run as\r
395                 soon as we unblocked. */\r
396                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
397                 {\r
398                         xErrorOccurred = pdTRUE;\r
399                 }\r
400 \r
401                 /* Suspend ready for test 3. */\r
402                 xRunIndicator = bktRUN_INDICATOR;\r
403                 vTaskSuspend( NULL );\r
404 \r
405                 /*********************************************************************\r
406         Test 4\r
407 \r
408                 As per test three, but with the send and receive reversed. */\r
409                 xTimeWhenBlocking = xTaskGetTickCount();\r
410 \r
411                 /* We should unblock after bktTIME_TO_BLOCK having not received\r
412                 anything on the queue. */\r
413                 xRunIndicator = bktRUN_INDICATOR;\r
414                 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )\r
415                 {\r
416                         xErrorOccurred = pdTRUE;\r
417                 }\r
418 \r
419                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
420 \r
421                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
422                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
423                 {\r
424                         xErrorOccurred = pdTRUE;\r
425                 }\r
426 \r
427                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
428                 either.  A margin is permitted as we would not necessarily run as soon\r
429                 as we unblocked. */\r
430                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
431                 {\r
432                         xErrorOccurred = pdTRUE;\r
433                 }\r
434 \r
435                 xRunIndicator = bktRUN_INDICATOR;\r
436 \r
437                 xSecondaryCycles++;\r
438         }\r
439 }\r
440 /*-----------------------------------------------------------*/\r
441 \r
442 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )\r
443 {\r
444 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;\r
445 portBASE_TYPE xReturn = pdPASS;\r
446 \r
447         /* Have both tasks performed at least one cycle since this function was\r
448         last called? */\r
449         if( xPrimaryCycles == xLastPrimaryCycleCount )\r
450         {\r
451                 xReturn = pdFAIL;\r
452         }\r
453 \r
454         if( xSecondaryCycles == xLastSecondaryCycleCount )\r
455         {\r
456                 xReturn = pdFAIL;\r
457         }\r
458 \r
459         if( xErrorOccurred == pdTRUE )\r
460         {\r
461                 xReturn = pdFAIL;\r
462         }\r
463 \r
464         xLastSecondaryCycleCount = xSecondaryCycles;\r
465         xLastPrimaryCycleCount = xPrimaryCycles;\r
466 \r
467         return xReturn;\r
468 }\r