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