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.

Continue to page two >>  

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

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.