Event flag groups: introduction and basic services
Event flag groups were introduced in an earlier article. In Nucleus SE, they are somewhat similar to signals, but with greater flexibility. They provide a low cost, but flexible, means of passing simple messages between tasks.
Using Event Flags
In Nucleus SE, event flags are configured at build time. There may be a maximum of 16 event flag groups configured for an application. If no event flag groups are configured, no data structures or service call code appertaining to event flag groups are included in the application.
An event flag group is simply a set of eight 1-bit flags, access to which is controlled so that it may be safely utilized by multiple tasks. One task can set or clear any combination of event flags. Another task may read the event flag group at any time or may wait (polling or suspended) for a specific pattern of flags.
Configuring Event Flag Groups
Number of Event Flag Groups
As with most aspects of Nucleus SE, the configuration of event flag groups is primarily controlled by #define statements in nuse_config.h . The key setting is NUSE_EVENT_GROUP_NUMBER , which determines how many event flag groups are configured for the application. The default setting is 0 (i.e. no event flag groups are in use) and you can set it to any value up to 16. An erroneous value will result in a compile time error, which is generated by a test in nuse_config_check.h (this is included into nuse_config.c and hence compiled with this module) resulting in a #error statement being compiled.
Choosing a non-zero value is the “master enable” for event flag groups. This results in some data structures being defined and sized accordingly, of which more later in this series. It also activates the API enabling settings.
API Enables
Every API function (service call) in Nucleus SE has an enabling #define symbol in nuse_config.h . For event flag groups, these are:
NUSE_EVENT_GROUP_SETNUSE_EVENT_GROUP_RETRIEVENUSE_EVENT_GROUP_INFORMATIONNUSE_EVENT_GROUP_COUNT
By default, all of these are set to FALSE , thus disabling each service call and inhibiting the inclusion of any implementation code. To configure event flag groups for an application, you need to select the API calls that you want to use and set their enabling symbols to TRUE .
Here is an extract from the default nuse_config.h file.
#define NUSE_EVENT_GROUP_NUMBER 0 /* Number of event groups in the system - 0-16 */#define NUSE_EVENT_GROUP_SET FALSE /* Service call enabler */#define NUSE_EVENT_GROUP_RETRIEVE FALSE /* Service call enabler */#define NUSE_EVENT_GROUP_INFORMATION FALSE /* Service call enabler */#define NUSE_EVENT_GROUP_COUNT FALSE /* Service call enabler */
A compile time error will result if an event flag group API function is enabled and no event flag groups are configured (except for NUSE_Event_Group_Count() which is always permitted). If your code uses an API call, which has not been enabled, a link time error will result, as no implementation code will have been included in the application.
Event Flag Service Calls
Nucleus RTOS supports seven service calls that appertain to event flags, which provide the following functionality:
-
Set event flags. Implemented by NUSE_Event_Group_Set() in Nucleus SE.
-
Retrieve event flags. Implemented by NUSE_Event_Group_Retrieve() in Nucleus SE.
-
Provide information about a specified event flag group. Implemented by NUSE_Event_Group_Information() in Nucleus SE.
-
Return a count of how many event flag groups are (currently) configured for the application. Implemented by NUSE_Event_Group_Count() in Nucleus SE.
-
Add a new event flag group to the application (create). Not implemented in Nucleus SE.
-
Remove an event flag group from the application (delete). Not implemented in Nucleus SE.
-
Return pointers to all the event flag groups (currently) in the application. Not implemented in Nucleus SE.
The implementation of each of these service calls is examined in detail.
It may be noted that there is no reset function is provided (in either Nucleus RTOS or Nucleus SE). This is intentional. A reset implies a special condition is prevailing. For an event flag group, the only “special” condition would be all zeros, which can be set up with NUSE_Event_Group_Set() .
Event Flag Group Set and Retrieve Services
The fundamental operations, which can be performed on an event flag group, are setting one or more flags and retrieving the current states of the flags. Nucleus RTOS and Nucleus SE each provide two basic API calls for these operations, which will be discussed here.
Since event flags are bits, they are best visualized as binary numbers. As standard C does not support a representation of binary constants (only octal and hexadecimal), the Nucleus SE distribution includes a useful header file – nuse_binary.h – which contains #define symbols of the form b01010101 for all 256 8-bit values.
Setting Event Flags
The Nucleus RTOS API call for setting event flags is very flexible, enabling you to set and clear event flags using AND and OR operations. Nucleus SE provides the same service, except task suspend is optional.
Nucleus RTOS API Call for Flag Setting
Service call prototype:
STATUS NU_Set_Events(NU_EVENT_GROUP *group, UNSIGNED event_flags,
OPTION operation);
Parameters:
group – pointer to the user-supplied event flag group control block
event_flags – the bit value of the pattern of flags to be operated upon
operation – the operation to be performed; may be NU_OR (to set flags) or NU_AND (to clear flags)
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_GROUP – the event flag group pointer is invalid
NU_INVALID_OPERATION – the specified operation was not NU_OR or NU_AND
Nucleus SE API Call for Flag Setting
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Event_Group_Set(NUSE_EVENT_GROUP group,
U8 event_flags, OPTION operation);
Parameters:
group – the index (ID) of the event group in which flags are to be set/cleared
event_flags – the bit value of the pattern of flags to be operated upon
operation – the operation to be performed; may be NUSE_OR (to set flags) or NUSE_AND (to clear flags)
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_GROUP – the event flag group index is invalid
NUSE_INVALID_OPERATION – the specified operation was not NUSE_OR or NUSE_AND
Nucleus SE Implementation of Set Event Flags
The initial code of the NUSE_ Event_Group_Set() API function – after parameter checking – is common, whether support for blocking (task suspend) API calls is enabled or not. The logic is quite simple:
NUSE_CS_Enter();if (operation == NUSE_OR){ NUSE_Event_Group_Data[group] |= event_flags;}else /* NUSE_AND */{ NUSE_Event_Group_Data[group] &= event_flags;}
The bit pattern, event_flags , is just ORed or ANDed into the specified event flag group.
The remaining code is only included if task blocking is enabled:
#if NUSE_BLOCKING_ENABLE while (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this event group */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_EVENT_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == group)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Event_Group_Blocking_Count[group]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif#endifNUSE_CS_Exit();return NUSE_SUCCESS;
If any tasks are suspended on (retrieving from) this event flag group, they are all resumed. When they have the opportunity to execute, which depends upon the scheduler, they can determine whether their conditions for return have been met – see Retrieving Event Flags below.
Retrieving Event Flags
The Nucleus RTOS API call for retrieving is very flexible, enabling you to suspend indefinitely, or with a timeout, if the operation cannot be completed immediately; i.e. you try to retrieve a specific pattern of event flags, which does not represent the current state. Nucleus SE provides the same service, except task suspend is optional and timeout is not implemented.
Nucleus RTOS API Call for Flag Retrieving
Service call prototype:
STATUS NU_Retrieve_Events(NU_EVENT_GROUP *group,
UNSIGNED requested_events, OPTION operation,UNSIGNED *retrieved_events, UNSIGNED suspend);
Parameters:
group – pointer to the user-supplied event flag group control block
requested_events – a bit pattern representing the flags to be retrieved
operation – there are four operation options available: NU_AND , NU_AND_CONSUME , NU_OR , and NU_OR_CONSUME . NU_AND and NU_AND_CONSUME options indicate that all of the requested event flags are required. NU_OR and NU_OR_CONSUME options indicate that one or more of the requested event flags is sufficient. The CONSUME option automatically clears the event flags present on a successful request.
retrieved_events – a pointer to storage for the actual value of the retrieved event flags
suspend – specification for task suspend; may be NU_NO_SUSPEND or NUSE_SUSPEND or a timeout value in ticks (1 – 4,294,967,293)
Returns:
NU_SUCCESS – the call was completed successfully
NU_NOT_PRESENT – specified operation did not retrieve events (none present for NU_OR ; not all present for NU_AND )
NU_INVALID_GROUP – the event flag group pointer is invalid
NU_INVALID_OPERATION – the specified operation was invalid
NU_INVALID_POINTER – the pointer to retrieved event flag storage is NULL
NU_INVALID_SUSPEND – suspend was attempted from a non-task thread
NU_TIMEOUT – the requested event flag combination is not present even after the specified suspension timeout
NU_GROUP_DELETED – the event flag group was deleted while the task was suspended
Nucleus SE API Call for Flag Retrieving
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Event_Group_Retrieve(NUSE_EVENT_GROUP group,
U8 requested_events, OPTION operation, U8 *retrieved_events,U8 suspend);
Parameters:
group – the index (ID) of the event flag group to be utilized
requested_events – a bit pattern representing the flags to be retrieved
operation – specification for whether all or just some of the requested events need to be present; may be NUSE_OR (some flags) or NUSE_AND (all flags)
retrieved_events – a pointer to storage for the actual value of the retrieved event flags (same value as requested_events if operation was NUSE_AND )
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_NOT_PRESENT – specified operation did not retrieve events (none present for NUSE_OR ; not all present for NUSE_AND )
NUSE_INVALID_GROUP – the event flag group index is invalid
NUSE_INVALID_OPERATION – the specified operation was not NUSE_OR or NUSE_AND
NUSE_INVALID_POINTER – the pointer to retrieved event flag storage is NULL
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
Nucleus SE Implementation of Retrieve Event Flags
The bulk of the code of the NUSE_Event_Group_Retrieve() API function – after parameter checking – is selected by conditional compilation, dependent upon whether support for blocking (task suspend) API calls is enabled. We will look at the two variants separately here.
If blocking is not enabled, the full code for this API call is as follows:
temp_events = NUSE_Event_Group_Data[group] & requested_events;if (operation == NUSE_OR){ if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; }}else /* operation == NUSE_AND */{ if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; }}
The required event flags are extracted from the specified event flag group. This value is compared with the required events, taking into account the AND /OR operation and the result returned, along with the actual value of the requested flags.
When blocking is enabled, the code becomes more complex:
do{ temp_events = NUSE_Event_Group_Data[group] & requested_events; if (operation == NUSE_OR) { if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } else /* operation == NUSE_AND */ { if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } if (return_value == NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_SUSPEND) /* block task */ { NUSE_Event_Group_Blocking_Count[group]++; NUSE_Suspend_Task(NUSE_Task_Active, (group << 4) | NUSE_EVENT_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } }} while (suspend == NUSE_SUSPEND);
The code is enclosed in a do…while loop, which continues while the parameter suspend has the value NUSE_SUSPEND .
The required event flags are retrieved in the same way as with a non-blocking call. If the retrieve is not successful and suspend is set to NUSE_NO_SUSPEND , the API call exits with NUSE_NOT_PRESENT . If suspend was set to NUSE_SUSPEND , the task is suspended. On return (i.e. when the task is woken up), if the return value is NUSE_SUCCESS , indicating that the task was woken because event flags in this group have been set or cleared, the code loops back to the top and the flags are retrieved and tested. Of course, since there is no reset API function for event flag groups, this is the only possible reason for the task to be woken, but the process of checking NUSE_Task_Blocking_Return[] is retained for consistency with the handling of blocking with other object types.
The next article will cover some additional API calls associated with event flag groups, along with the relevant data structures.
Colin Walls has over thirty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, Colin is an embedded software technologist with Mentor Embedded [the Mentor Graphics Embedded Software Division], and is based in the UK. His regular blog is located at: http://blogs.mentor.com/colinwalls. He may be reached by email at colin_walls@mentor.com