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