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