]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/event_groups.c
51cae81ee3aec74c204e914da2075665819894e7
[freertos] / FreeRTOS / Source / event_groups.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 /* Standard includes. */\r
29 #include <stdlib.h>\r
30 \r
31 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
32 all the API functions to use the MPU wrappers.  That should only be done when\r
33 task.h is included from an application file. */\r
34 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
35 \r
36 /* FreeRTOS includes. */\r
37 #include "FreeRTOS.h"\r
38 #include "task.h"\r
39 #include "timers.h"\r
40 #include "event_groups.h"\r
41 \r
42 /* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified\r
43 because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined\r
44 for the header files above, but not in this file, in order to generate the\r
45 correct privileged Vs unprivileged linkage and placement. */\r
46 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */\r
47 \r
48 /* The following bit fields convey control information in a task's event list\r
49 item value.  It is important they don't clash with the\r
50 taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */\r
51 #if configUSE_16_BIT_TICKS == 1\r
52         #define eventCLEAR_EVENTS_ON_EXIT_BIT   0x0100U\r
53         #define eventUNBLOCKED_DUE_TO_BIT_SET   0x0200U\r
54         #define eventWAIT_FOR_ALL_BITS                  0x0400U\r
55         #define eventEVENT_BITS_CONTROL_BYTES   0xff00U\r
56 #else\r
57         #define eventCLEAR_EVENTS_ON_EXIT_BIT   0x01000000UL\r
58         #define eventUNBLOCKED_DUE_TO_BIT_SET   0x02000000UL\r
59         #define eventWAIT_FOR_ALL_BITS                  0x04000000UL\r
60         #define eventEVENT_BITS_CONTROL_BYTES   0xff000000UL\r
61 #endif\r
62 \r
63 typedef struct EventGroupDef_t\r
64 {\r
65         EventBits_t uxEventBits;\r
66         List_t xTasksWaitingForBits;            /*< List of tasks waiting for a bit to be set. */\r
67 \r
68         #if( configUSE_TRACE_FACILITY == 1 )\r
69                 UBaseType_t uxEventGroupNumber;\r
70         #endif\r
71 \r
72         #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )\r
73                 uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */\r
74         #endif\r
75 } EventGroup_t;\r
76 \r
77 /*-----------------------------------------------------------*/\r
78 \r
79 /*\r
80  * Test the bits set in uxCurrentEventBits to see if the wait condition is met.\r
81  * The wait condition is defined by xWaitForAllBits.  If xWaitForAllBits is\r
82  * pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor\r
83  * are also set in uxCurrentEventBits.  If xWaitForAllBits is pdFALSE then the\r
84  * wait condition is met if any of the bits set in uxBitsToWait for are also set\r
85  * in uxCurrentEventBits.\r
86  */\r
87 static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;\r
88 \r
89 /*-----------------------------------------------------------*/\r
90 \r
91 #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
92 \r
93         EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )\r
94         {\r
95         EventGroup_t *pxEventBits;\r
96 \r
97                 /* A StaticEventGroup_t object must be provided. */\r
98                 configASSERT( pxEventGroupBuffer );\r
99 \r
100                 #if( configASSERT_DEFINED == 1 )\r
101                 {\r
102                         /* Sanity check that the size of the structure used to declare a\r
103                         variable of type StaticEventGroup_t equals the size of the real\r
104                         event group structure. */\r
105                         volatile size_t xSize = sizeof( StaticEventGroup_t );\r
106                         configASSERT( xSize == sizeof( EventGroup_t ) );\r
107                 } /*lint !e529 xSize is referenced if configASSERT() is defined. */\r
108                 #endif /* configASSERT_DEFINED */\r
109 \r
110                 /* The user has provided a statically allocated event group - use it. */\r
111                 pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */\r
112 \r
113                 if( pxEventBits != NULL )\r
114                 {\r
115                         pxEventBits->uxEventBits = 0;\r
116                         vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );\r
117 \r
118                         #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
119                         {\r
120                                 /* Both static and dynamic allocation can be used, so note that\r
121                                 this event group was created statically in case the event group\r
122                                 is later deleted. */\r
123                                 pxEventBits->ucStaticallyAllocated = pdTRUE;\r
124                         }\r
125                         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
126 \r
127                         traceEVENT_GROUP_CREATE( pxEventBits );\r
128                 }\r
129                 else\r
130                 {\r
131                         /* xEventGroupCreateStatic should only ever be called with\r
132                         pxEventGroupBuffer pointing to a pre-allocated (compile time\r
133                         allocated) StaticEventGroup_t variable. */\r
134                         traceEVENT_GROUP_CREATE_FAILED();\r
135                 }\r
136 \r
137                 return pxEventBits;\r
138         }\r
139 \r
140 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
141 /*-----------------------------------------------------------*/\r
142 \r
143 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
144 \r
145         EventGroupHandle_t xEventGroupCreate( void )\r
146         {\r
147         EventGroup_t *pxEventBits;\r
148 \r
149                 /* Allocate the event group.  Justification for MISRA deviation as\r
150                 follows:  pvPortMalloc() always ensures returned memory blocks are\r
151                 aligned per the requirements of the MCU stack.  In this case\r
152                 pvPortMalloc() must return a pointer that is guaranteed to meet the\r
153                 alignment requirements of the EventGroup_t structure - which (if you\r
154                 follow it through) is the alignment requirements of the TickType_t type\r
155                 (EventBits_t being of TickType_t itself).  Therefore, whenever the\r
156                 stack alignment requirements are greater than or equal to the\r
157                 TickType_t alignment requirements the cast is safe.  In other cases,\r
158                 where the natural word size of the architecture is less than\r
159                 sizeof( TickType_t ), the TickType_t variables will be accessed in two\r
160                 or more reads operations, and the alignment requirements is only that\r
161                 of each individual read. */\r
162                 pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */\r
163 \r
164                 if( pxEventBits != NULL )\r
165                 {\r
166                         pxEventBits->uxEventBits = 0;\r
167                         vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );\r
168 \r
169                         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
170                         {\r
171                                 /* Both static and dynamic allocation can be used, so note this\r
172                                 event group was allocated statically in case the event group is\r
173                                 later deleted. */\r
174                                 pxEventBits->ucStaticallyAllocated = pdFALSE;\r
175                         }\r
176                         #endif /* configSUPPORT_STATIC_ALLOCATION */\r
177 \r
178                         traceEVENT_GROUP_CREATE( pxEventBits );\r
179                 }\r
180                 else\r
181                 {\r
182                         traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */\r
183                 }\r
184 \r
185                 return pxEventBits;\r
186         }\r
187 \r
188 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
189 /*-----------------------------------------------------------*/\r
190 \r
191 EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )\r
192 {\r
193 EventBits_t uxOriginalBitValue, uxReturn;\r
194 EventGroup_t *pxEventBits = xEventGroup;\r
195 BaseType_t xAlreadyYielded;\r
196 BaseType_t xTimeoutOccurred = pdFALSE;\r
197 \r
198         configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );\r
199         configASSERT( uxBitsToWaitFor != 0 );\r
200         #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )\r
201         {\r
202                 configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );\r
203         }\r
204         #endif\r
205 \r
206         vTaskSuspendAll();\r
207         {\r
208                 uxOriginalBitValue = pxEventBits->uxEventBits;\r
209 \r
210                 ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );\r
211 \r
212                 if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )\r
213                 {\r
214                         /* All the rendezvous bits are now set - no need to block. */\r
215                         uxReturn = ( uxOriginalBitValue | uxBitsToSet );\r
216 \r
217                         /* Rendezvous always clear the bits.  They will have been cleared\r
218                         already unless this is the only task in the rendezvous. */\r
219                         pxEventBits->uxEventBits &= ~uxBitsToWaitFor;\r
220 \r
221                         xTicksToWait = 0;\r
222                 }\r
223                 else\r
224                 {\r
225                         if( xTicksToWait != ( TickType_t ) 0 )\r
226                         {\r
227                                 traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );\r
228 \r
229                                 /* Store the bits that the calling task is waiting for in the\r
230                                 task's event list item so the kernel knows when a match is\r
231                                 found.  Then enter the blocked state. */\r
232                                 vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );\r
233 \r
234                                 /* This assignment is obsolete as uxReturn will get set after\r
235                                 the task unblocks, but some compilers mistakenly generate a\r
236                                 warning about uxReturn being returned without being set if the\r
237                                 assignment is omitted. */\r
238                                 uxReturn = 0;\r
239                         }\r
240                         else\r
241                         {\r
242                                 /* The rendezvous bits were not set, but no block time was\r
243                                 specified - just return the current event bit value. */\r
244                                 uxReturn = pxEventBits->uxEventBits;\r
245                                 xTimeoutOccurred = pdTRUE;\r
246                         }\r
247                 }\r
248         }\r
249         xAlreadyYielded = xTaskResumeAll();\r
250 \r
251         if( xTicksToWait != ( TickType_t ) 0 )\r
252         {\r
253                 if( xAlreadyYielded == pdFALSE )\r
254                 {\r
255                         portYIELD_WITHIN_API();\r
256                 }\r
257                 else\r
258                 {\r
259                         mtCOVERAGE_TEST_MARKER();\r
260                 }\r
261 \r
262                 /* The task blocked to wait for its required bits to be set - at this\r
263                 point either the required bits were set or the block time expired.  If\r
264                 the required bits were set they will have been stored in the task's\r
265                 event list item, and they should now be retrieved then cleared. */\r
266                 uxReturn = uxTaskResetEventItemValue();\r
267 \r
268                 if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )\r
269                 {\r
270                         /* The task timed out, just return the current event bit value. */\r
271                         taskENTER_CRITICAL();\r
272                         {\r
273                                 uxReturn = pxEventBits->uxEventBits;\r
274 \r
275                                 /* Although the task got here because it timed out before the\r
276                                 bits it was waiting for were set, it is possible that since it\r
277                                 unblocked another task has set the bits.  If this is the case\r
278                                 then it needs to clear the bits before exiting. */\r
279                                 if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )\r
280                                 {\r
281                                         pxEventBits->uxEventBits &= ~uxBitsToWaitFor;\r
282                                 }\r
283                                 else\r
284                                 {\r
285                                         mtCOVERAGE_TEST_MARKER();\r
286                                 }\r
287                         }\r
288                         taskEXIT_CRITICAL();\r
289 \r
290                         xTimeoutOccurred = pdTRUE;\r
291                 }\r
292                 else\r
293                 {\r
294                         /* The task unblocked because the bits were set. */\r
295                 }\r
296 \r
297                 /* Control bits might be set as the task had blocked should not be\r
298                 returned. */\r
299                 uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;\r
300         }\r
301 \r
302         traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );\r
303 \r
304         /* Prevent compiler warnings when trace macros are not used. */\r
305         ( void ) xTimeoutOccurred;\r
306 \r
307         return uxReturn;\r
308 }\r
309 /*-----------------------------------------------------------*/\r
310 \r
311 EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )\r
312 {\r
313 EventGroup_t *pxEventBits = xEventGroup;\r
314 EventBits_t uxReturn, uxControlBits = 0;\r
315 BaseType_t xWaitConditionMet, xAlreadyYielded;\r
316 BaseType_t xTimeoutOccurred = pdFALSE;\r
317 \r
318         /* Check the user is not attempting to wait on the bits used by the kernel\r
319         itself, and that at least one bit is being requested. */\r
320         configASSERT( xEventGroup );\r
321         configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );\r
322         configASSERT( uxBitsToWaitFor != 0 );\r
323         #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )\r
324         {\r
325                 configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );\r
326         }\r
327         #endif\r
328 \r
329         vTaskSuspendAll();\r
330         {\r
331                 const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;\r
332 \r
333                 /* Check to see if the wait condition is already met or not. */\r
334                 xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );\r
335 \r
336                 if( xWaitConditionMet != pdFALSE )\r
337                 {\r
338                         /* The wait condition has already been met so there is no need to\r
339                         block. */\r
340                         uxReturn = uxCurrentEventBits;\r
341                         xTicksToWait = ( TickType_t ) 0;\r
342 \r
343                         /* Clear the wait bits if requested to do so. */\r
344                         if( xClearOnExit != pdFALSE )\r
345                         {\r
346                                 pxEventBits->uxEventBits &= ~uxBitsToWaitFor;\r
347                         }\r
348                         else\r
349                         {\r
350                                 mtCOVERAGE_TEST_MARKER();\r
351                         }\r
352                 }\r
353                 else if( xTicksToWait == ( TickType_t ) 0 )\r
354                 {\r
355                         /* The wait condition has not been met, but no block time was\r
356                         specified, so just return the current value. */\r
357                         uxReturn = uxCurrentEventBits;\r
358                         xTimeoutOccurred = pdTRUE;\r
359                 }\r
360                 else\r
361                 {\r
362                         /* The task is going to block to wait for its required bits to be\r
363                         set.  uxControlBits are used to remember the specified behaviour of\r
364                         this call to xEventGroupWaitBits() - for use when the event bits\r
365                         unblock the task. */\r
366                         if( xClearOnExit != pdFALSE )\r
367                         {\r
368                                 uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;\r
369                         }\r
370                         else\r
371                         {\r
372                                 mtCOVERAGE_TEST_MARKER();\r
373                         }\r
374 \r
375                         if( xWaitForAllBits != pdFALSE )\r
376                         {\r
377                                 uxControlBits |= eventWAIT_FOR_ALL_BITS;\r
378                         }\r
379                         else\r
380                         {\r
381                                 mtCOVERAGE_TEST_MARKER();\r
382                         }\r
383 \r
384                         /* Store the bits that the calling task is waiting for in the\r
385                         task's event list item so the kernel knows when a match is\r
386                         found.  Then enter the blocked state. */\r
387                         vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );\r
388 \r
389                         /* This is obsolete as it will get set after the task unblocks, but\r
390                         some compilers mistakenly generate a warning about the variable\r
391                         being returned without being set if it is not done. */\r
392                         uxReturn = 0;\r
393 \r
394                         traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );\r
395                 }\r
396         }\r
397         xAlreadyYielded = xTaskResumeAll();\r
398 \r
399         if( xTicksToWait != ( TickType_t ) 0 )\r
400         {\r
401                 if( xAlreadyYielded == pdFALSE )\r
402                 {\r
403                         portYIELD_WITHIN_API();\r
404                 }\r
405                 else\r
406                 {\r
407                         mtCOVERAGE_TEST_MARKER();\r
408                 }\r
409 \r
410                 /* The task blocked to wait for its required bits to be set - at this\r
411                 point either the required bits were set or the block time expired.  If\r
412                 the required bits were set they will have been stored in the task's\r
413                 event list item, and they should now be retrieved then cleared. */\r
414                 uxReturn = uxTaskResetEventItemValue();\r
415 \r
416                 if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )\r
417                 {\r
418                         taskENTER_CRITICAL();\r
419                         {\r
420                                 /* The task timed out, just return the current event bit value. */\r
421                                 uxReturn = pxEventBits->uxEventBits;\r
422 \r
423                                 /* It is possible that the event bits were updated between this\r
424                                 task leaving the Blocked state and running again. */\r
425                                 if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )\r
426                                 {\r
427                                         if( xClearOnExit != pdFALSE )\r
428                                         {\r
429                                                 pxEventBits->uxEventBits &= ~uxBitsToWaitFor;\r
430                                         }\r
431                                         else\r
432                                         {\r
433                                                 mtCOVERAGE_TEST_MARKER();\r
434                                         }\r
435                                 }\r
436                                 else\r
437                                 {\r
438                                         mtCOVERAGE_TEST_MARKER();\r
439                                 }\r
440                                 xTimeoutOccurred = pdTRUE;\r
441                         }\r
442                         taskEXIT_CRITICAL();\r
443                 }\r
444                 else\r
445                 {\r
446                         /* The task unblocked because the bits were set. */\r
447                 }\r
448 \r
449                 /* The task blocked so control bits may have been set. */\r
450                 uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;\r
451         }\r
452         traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );\r
453 \r
454         /* Prevent compiler warnings when trace macros are not used. */\r
455         ( void ) xTimeoutOccurred;\r
456 \r
457         return uxReturn;\r
458 }\r
459 /*-----------------------------------------------------------*/\r
460 \r
461 EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )\r
462 {\r
463 EventGroup_t *pxEventBits = xEventGroup;\r
464 EventBits_t uxReturn;\r
465 \r
466         /* Check the user is not attempting to clear the bits used by the kernel\r
467         itself. */\r
468         configASSERT( xEventGroup );\r
469         configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );\r
470 \r
471         taskENTER_CRITICAL();\r
472         {\r
473                 traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );\r
474 \r
475                 /* The value returned is the event group value prior to the bits being\r
476                 cleared. */\r
477                 uxReturn = pxEventBits->uxEventBits;\r
478 \r
479                 /* Clear the bits. */\r
480                 pxEventBits->uxEventBits &= ~uxBitsToClear;\r
481         }\r
482         taskEXIT_CRITICAL();\r
483 \r
484         return uxReturn;\r
485 }\r
486 /*-----------------------------------------------------------*/\r
487 \r
488 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )\r
489 \r
490         BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )\r
491         {\r
492                 BaseType_t xReturn;\r
493 \r
494                 traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );\r
495                 xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */\r
496 \r
497                 return xReturn;\r
498         }\r
499 \r
500 #endif\r
501 /*-----------------------------------------------------------*/\r
502 \r
503 EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )\r
504 {\r
505 UBaseType_t uxSavedInterruptStatus;\r
506 EventGroup_t const * const pxEventBits = xEventGroup;\r
507 EventBits_t uxReturn;\r
508 \r
509         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
510         {\r
511                 uxReturn = pxEventBits->uxEventBits;\r
512         }\r
513         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
514 \r
515         return uxReturn;\r
516 } /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */\r
517 /*-----------------------------------------------------------*/\r
518 \r
519 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )\r
520 {\r
521 ListItem_t *pxListItem, *pxNext;\r
522 ListItem_t const *pxListEnd;\r
523 List_t const * pxList;\r
524 EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;\r
525 EventGroup_t *pxEventBits = xEventGroup;\r
526 BaseType_t xMatchFound = pdFALSE;\r
527 \r
528         /* Check the user is not attempting to set the bits used by the kernel\r
529         itself. */\r
530         configASSERT( xEventGroup );\r
531         configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );\r
532 \r
533         pxList = &( pxEventBits->xTasksWaitingForBits );\r
534         pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM.  This is checked and valid. */\r
535         vTaskSuspendAll();\r
536         {\r
537                 traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );\r
538 \r
539                 pxListItem = listGET_HEAD_ENTRY( pxList );\r
540 \r
541                 /* Set the bits. */\r
542                 pxEventBits->uxEventBits |= uxBitsToSet;\r
543 \r
544                 /* See if the new bit value should unblock any tasks. */\r
545                 while( pxListItem != pxListEnd )\r
546                 {\r
547                         pxNext = listGET_NEXT( pxListItem );\r
548                         uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );\r
549                         xMatchFound = pdFALSE;\r
550 \r
551                         /* Split the bits waited for from the control bits. */\r
552                         uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;\r
553                         uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;\r
554 \r
555                         if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )\r
556                         {\r
557                                 /* Just looking for single bit being set. */\r
558                                 if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )\r
559                                 {\r
560                                         xMatchFound = pdTRUE;\r
561                                 }\r
562                                 else\r
563                                 {\r
564                                         mtCOVERAGE_TEST_MARKER();\r
565                                 }\r
566                         }\r
567                         else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )\r
568                         {\r
569                                 /* All bits are set. */\r
570                                 xMatchFound = pdTRUE;\r
571                         }\r
572                         else\r
573                         {\r
574                                 /* Need all bits to be set, but not all the bits were set. */\r
575                         }\r
576 \r
577                         if( xMatchFound != pdFALSE )\r
578                         {\r
579                                 /* The bits match.  Should the bits be cleared on exit? */\r
580                                 if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )\r
581                                 {\r
582                                         uxBitsToClear |= uxBitsWaitedFor;\r
583                                 }\r
584                                 else\r
585                                 {\r
586                                         mtCOVERAGE_TEST_MARKER();\r
587                                 }\r
588 \r
589                                 /* Store the actual event flag value in the task's event list\r
590                                 item before removing the task from the event list.  The\r
591                                 eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows\r
592                                 that is was unblocked due to its required bits matching, rather\r
593                                 than because it timed out. */\r
594                                 vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );\r
595                         }\r
596 \r
597                         /* Move onto the next list item.  Note pxListItem->pxNext is not\r
598                         used here as the list item may have been removed from the event list\r
599                         and inserted into the ready/pending reading list. */\r
600                         pxListItem = pxNext;\r
601                 }\r
602 \r
603                 /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT\r
604                 bit was set in the control word. */\r
605                 pxEventBits->uxEventBits &= ~uxBitsToClear;\r
606         }\r
607         ( void ) xTaskResumeAll();\r
608 \r
609         return pxEventBits->uxEventBits;\r
610 }\r
611 /*-----------------------------------------------------------*/\r
612 \r
613 void vEventGroupDelete( EventGroupHandle_t xEventGroup )\r
614 {\r
615 EventGroup_t *pxEventBits = xEventGroup;\r
616 const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );\r
617 \r
618         vTaskSuspendAll();\r
619         {\r
620                 traceEVENT_GROUP_DELETE( xEventGroup );\r
621 \r
622                 while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )\r
623                 {\r
624                         /* Unblock the task, returning 0 as the event list is being deleted\r
625                         and cannot therefore have any bits set. */\r
626                         configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );\r
627                         vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );\r
628                 }\r
629 \r
630                 #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )\r
631                 {\r
632                         /* The event group can only have been allocated dynamically - free\r
633                         it again. */\r
634                         vPortFree( pxEventBits );\r
635                 }\r
636                 #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )\r
637                 {\r
638                         /* The event group could have been allocated statically or\r
639                         dynamically, so check before attempting to free the memory. */\r
640                         if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )\r
641                         {\r
642                                 vPortFree( pxEventBits );\r
643                         }\r
644                         else\r
645                         {\r
646                                 mtCOVERAGE_TEST_MARKER();\r
647                         }\r
648                 }\r
649                 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
650         }\r
651         ( void ) xTaskResumeAll();\r
652 }\r
653 /*-----------------------------------------------------------*/\r
654 \r
655 /* For internal use only - execute a 'set bits' command that was pended from\r
656 an interrupt. */\r
657 void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet )\r
658 {\r
659         ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */\r
660 }\r
661 /*-----------------------------------------------------------*/\r
662 \r
663 /* For internal use only - execute a 'clear bits' command that was pended from\r
664 an interrupt. */\r
665 void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear )\r
666 {\r
667         ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */\r
668 }\r
669 /*-----------------------------------------------------------*/\r
670 \r
671 static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )\r
672 {\r
673 BaseType_t xWaitConditionMet = pdFALSE;\r
674 \r
675         if( xWaitForAllBits == pdFALSE )\r
676         {\r
677                 /* Task only has to wait for one bit within uxBitsToWaitFor to be\r
678                 set.  Is one already set? */\r
679                 if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )\r
680                 {\r
681                         xWaitConditionMet = pdTRUE;\r
682                 }\r
683                 else\r
684                 {\r
685                         mtCOVERAGE_TEST_MARKER();\r
686                 }\r
687         }\r
688         else\r
689         {\r
690                 /* Task has to wait for all the bits in uxBitsToWaitFor to be set.\r
691                 Are they set already? */\r
692                 if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )\r
693                 {\r
694                         xWaitConditionMet = pdTRUE;\r
695                 }\r
696                 else\r
697                 {\r
698                         mtCOVERAGE_TEST_MARKER();\r
699                 }\r
700         }\r
701 \r
702         return xWaitConditionMet;\r
703 }\r
704 /*-----------------------------------------------------------*/\r
705 \r
706 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )\r
707 \r
708         BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )\r
709         {\r
710         BaseType_t xReturn;\r
711 \r
712                 traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );\r
713                 xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */\r
714 \r
715                 return xReturn;\r
716         }\r
717 \r
718 #endif\r
719 /*-----------------------------------------------------------*/\r
720 \r
721 #if (configUSE_TRACE_FACILITY == 1)\r
722 \r
723         UBaseType_t uxEventGroupGetNumber( void* xEventGroup )\r
724         {\r
725         UBaseType_t xReturn;\r
726         EventGroup_t const *pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */\r
727 \r
728                 if( xEventGroup == NULL )\r
729                 {\r
730                         xReturn = 0;\r
731                 }\r
732                 else\r
733                 {\r
734                         xReturn = pxEventBits->uxEventGroupNumber;\r
735                 }\r
736 \r
737                 return xReturn;\r
738         }\r
739 \r
740 #endif /* configUSE_TRACE_FACILITY */\r
741 /*-----------------------------------------------------------*/\r
742 \r
743 #if ( configUSE_TRACE_FACILITY == 1 )\r
744 \r
745         void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber )\r
746         {\r
747                 ( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */\r
748         }\r
749 \r
750 #endif /* configUSE_TRACE_FACILITY */\r
751 /*-----------------------------------------------------------*/\r
752 \r
753 \r