
Groups of event flags have already been mentioned earlier in a previous article (# 5). In Nucleus SE, they look like signals, but are more flexible. They provide a low-cost and flexible way to transfer simple messages between tasks.
Previous articles in the series:
Article # 16. SignalsArticle # 15. Memory sections: services and data structuresArticle # 14. Memory sections: introduction and basic servicesArticle # 13. Task data structures and unsupported API callsArticle # 12. Task ServicesArticle # 11. Tasks: configuration and introduction to the APIArticle # 10. Scheduler: additional features and context preservationArticle # 9. Scheduler: implementationArticle # 8. Nucleus SE: Inside and DeploymentArticle # 7. Nucleus SE: introductionArticle # 6. Other RTOS servicesArticle # 5. Interaction between tasks and synchronizationArticle # 4. Tasks, context switching and interruptsArticle # 3. Tasks and planningArticle # 2. RTOS: Structure and Real Time
Article # 1. RTOS: introduction.
')
Using event flags
In Nucleus SE, event flags are defined at the build stage. The maximum number of event flag groups in the application is 16. If the event flag groups are not defined, the code related to the data structures and service calls of the event flag groups will not be included in the application.
A group of event flags is a set of eight bit flags, access to which is regulated in such a way that several tasks can be safely used by one flag. One task can set or clear any combination of event flags. Another task can read a group of flags at any time, and can also wait for a specific sequence of flags (by polling or with suspension).
Setting groups of event flags
Number of event flag groups
As with most Nucleus SE objects, the setting of groups of event flags is specified by the
#define directives in
nuse_config.h . The main parameter is
NUSE_EVENT_GROUP_NUMBER , which determines how many groups of event flags will be defined in the application. By default, this parameter is set to 0 (that is, groups of event flags are not used) and can have any value up to 16. An incorrect value will result in a compilation error, which will be generated by checking in
nuse_config_check.h (it is enabled by
nuse_config.c , which means it is compiled together with this module), as a result, the
#error directive will work. The choice of a non-zero value serves as the main activator of the event flag groups. This parameter is used when defining data structures and their size depends on its value (for more details, see the following articles). In addition, a non-zero value activates the API settings.
Activate API calls
Each API function (service call) in the Nucleus SE is activated by the
#define directive in
nuse_config.h . For groups of event flags, these include:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT
By default, they are assigned the value
FALSE , thus disabling each service call and blocking the inclusion of the code implementing them. To configure groups of event flags, select the necessary API calls and set the corresponding directives to
TRUE .
The following is an excerpt from the default nuse_config.h file.
#define NUSE_EVENT_GROUP_NUMBER 0 #define NUSE_EVENT_GROUP_SET FALSE #define NUSE_EVENT_GROUP_RETRIEVE FALSE #define NUSE_EVENT_GROUP_INFORMATION FALSE #define NUSE_EVENT_GROUP_COUNT FALSE
An activated API function if there are no event flag groups in the application will result in a compilation error (except
NUSE_Event_Group_Count () , which is always allowed). If your code uses an API call that has not been activated, a build error will occur because the implementation code was not included in the application.
Service Calls for Event Flags
Nucleus RTOS supports seven service calls that provide the following functionality:
- Setting event flags. The Nucleus SE is implemented in the NUSE_Event_Group_Set () function.
- Read event flags. In Nucleus SE, NUSE_Event_Group_Retrieve () is implemented.
- Providing information on a specific group of event flags. In Nucleus SE is implemented in NUSE_Event_Group_Information () .
- Return the number of currently configured event flag groups in the application. In Nucleus SE is implemented in NUSE_Event_Group_Count () .
- Adding a new group of event flags to the application. Nucleus SE is not implemented.
- Remove a group of event flags from an application. Nucleus SE is not implemented.
- Returning pointers to all groups of event flags in the application. Nucleus SE is not implemented.
The implementation of each of these service calls is detailed below.
It is worth noting that there is no reset function in either the Nucleus RTOS or the Nucleus SE. This is intentional. The reset function implies the predominance of a special state of flags. For groups of event flags, the only “special” state is the zeroing of all flags, which can be performed using
NUSE_Event_Group_Set () .
Service calls for setting and reading event flag groups
The fundamental operations that can be performed on a group of event flags are setting the value of one or more flags, as well as reading the current values of the flags. Nucleus RTOS and Nucleus SE provide four basic API calls for these operations.
Since event flags are bits, they are best rendered as binary numbers. Since standard C does not historically support the representation of binary constants (octal and hexadecimal only), Nucleus SE has a useful header file
nuse_binary.h , which contains
#define characters of the form
b01010101 for all 256 8-bit values.
Setting event flags
The Nucleus RTOS API service call for setting flags is very flexible and allows you to set and clear flag values using
AND and
OR operations. Nucleus SE provides similar functionality, but task suspension is optional.
Call to set flags in the Nucleus RTOSService Call Prototype:
STATUS NU_Set_Events (NU_EVENT_GROUP * group, UNSIGNED event_flags, OPTION operation);Options:
group — pointer to the user-provided control unit for the group of event flags;
event_flags - the bitmask value of the group of flags;
operation - the
operation to be performed,
NU_OR (to set flags) or
NU_AND (to clear flags).
Return value:
NU_SUCCESS - the call was successfully completed;
NU_INVALID_GROUP - incorrect pointer to the group of event flags;
NU_INVALID_OPERATION - the specified operation is different from
NU_OR and
NU_AND .
Call to set flags in the Nucleus SEThis API call supports the core Nucleus RTOS API.
Service Call Prototype:
STATUS NUSE_Event_Group_Set (NUSE_EVENT_GROUP group, U8 event_flags, OPTION operation);Options:
group - the index (ID) of the group of events whose flags are set / cleared;
event_flags - bit maxi flag group value;
operation - the
operation to be performed,
NUSE_OR (for setting flags) or
NUSE_AND (for cleaning flags).
Return value:
NUSE_SUCCESS - the call was successfully completed;
NUSE_INVALID_GROUP - incorrect index of the group of event flags;
NUSE_INVALID_OPERATION - the specified operation is different from
NUSE_OR and
NUSE_AND .
Implementing the setting of event flags in the Nucleus SEThe initial code of the
NUSE_Event_Group_Set () API function is common (after checking parameters), regardless of whether support for blocking calls (task suspension) is activated or not. The logic is pretty simple:
NUSE_CS_Enter(); if (operation == NUSE_OR) { NUSE_Event_Group_Data[group] |= event_flags; } else { NUSE_Event_Group_Data[group] &= event_flags; }
The
event_flags bitmask is superimposed (using an
AND or
OR operation) on the value of the selected group of event flags.
The remaining code is enabled only when the task lock is activated:
#if NUSE_BLOCKING_ENABLE while (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; 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 #endif NUSE_CS_Exit(); return NUSE_SUCCESS;
If any tasks are suspended (for reading) from this group of flags, they are resumed. When they are given the opportunity to continue execution (it depends on the scheduler), they can determine whether the conditions for their resumption are satisfied or not (see reading the event flags).
Reading event flags
Nucleus RTOS API read calls are very flexible and allow you to suspend tasks indefinitely or with a specific timeout if the operation cannot be performed immediately (for example, if you try to read a certain sequence of event flags that do not represent the current state). Nucleus SE provides the same functions, only task suspension is optional, and timeout is not implemented.
Call to read flags in the Nucleus RTOSService Call Prototype:
STATUS NU_Retrieve_Events (NU_EVENT_GROUP * group, UNSIGNED requested_events, OPTION operation, UNSIGNED * retrieved_events, UNSIGNED suspend);Options:
group — pointer to the user-provided control unit for the group of event flags;
requested_events - bitmask defining readable flags;
operation - four
operations are available:
NU_AND ,
NU_AND_CONSUME ,
NU_OR and
NU_OR_CONSUME . The
NU_AND and
NU_AND_CONSUME operations indicate that all requested flags are required. The
NU_OR and
NU_OR_CONSUME operations indicate that one or more of the requested flags are sufficient. The
CONSUME parameter automatically clears existing flags after a successful request;
retrieved_events - pointer to the repository for the values of readable event flags;
suspend - specification for suspending tasks; can be
NU_NO_SUSPEND or
NU_SUSPEND , or the timeout value in system timer
ticks (from 1 to 4,294,967,293).
Return value:
NU_SUCCESS - the call was successfully completed;
NU_NOT_PRESENT - the specified operation did not return an event (not a single event in the case of NU_OR and not all events in the case of NU_AND);
NU_INVALID_GROUP - incorrect pointer to the group of event flags;
NU_INVALID_OPERATION - the specified operation was incorrect;
NU_INVALID_POINTER — null pointer to the event flags storage (NULL);
NU_INVALID_SUSPEND - an attempt to suspend a non-task-related stream;
NU_TIMEOUT - the required combination of event flags was not set even after the specified timeout;
NU_GROUP_DELETED - the group of event flags was deleted, while the task was suspended.
A call to read flags in the Nucleus SEThis API call supports the core 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);Options:
group - index of the readout group of event flags;
requested_events - bitmask defining readable flags;
operation - specification indicating the number of flags required:
NUSE OR (some flags) or
NUSE AND (all flags);
retrieved_events - pointer to the repository for the actual values of the read event flags (for the
NUSE_AND operation
, this will be the same as that passed in the
requested_events parameter);
suspend - specification for pausing the task, can be
NUSE_NO_SUSPEND or
NUSE_SUSPEND .
Return value:
NUSE_SUCCESS - the call was successfully completed;
NUSE_NOT_PRESENT - the specified operation did not return an event (not a single event in the case of
NUSE_OR and not all events in the case of
NUSE_AND );
NUSE_INVALID_GROUP - incorrect index of the group of event flags;
NUSE_INVALID_OPERATION - the specified operation is different from
NUSE_OR or
NUSE_AND ;
NUSE_INVALID_POINTER - null pointer to the storage of read event flags (
NULL );
NUSE_INVALID_SUSPEND - an attempt to pause from a
thread that is not associated with a task or when support for blocking API calls is disabled.
Implementing the reading of event flags in the Nucleus SEThe code variant of the
NUSE_Event_Group_Retrieve () API function (after checking the parameters) is selected during conditional compilation depending on whether support for call blocking (suspension) of API calls is activated or not. Consider these two options separately.
If the lock is disabled, the full code for this API call will look like this:
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 selected from the specified group of event flags. The value is compared with the required events, taking into account the
AND / OR operation, as well as the return result and the immediate values of the requested flags.
If task lock is activated, 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 { 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) { 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 placed in a
do ... while loop , which works while the
suspend parameter is
NUSE_SUSPEND .
The requested event flags are read the same way as when calling without blocking. If the read is not successful and the
suspend parameter is
NUSE_NO_SUSPEND , the API call is assigned the value
NUSE_NOT_PRESENT . If the
suspend parameter was set to
NUSE_SUSPEND , the task is suspended. On return (when the task is resumed), if the return value is
NUSE_SUCCESS , indicating that the task has been resumed because the event flags in this group have been set or cleared, the cycle starts from the beginning, the flags are read and checked. Since there is no API function for resetting groups of event flags, this is the only reason for resuming the task, but the
NUSE_Task_Blocking_Return [] checkout process was left on the system for lock control compatibility with other types of objects.
The next article will describe additional API calls related to groups of event flags, as well as their data structures.
About the author: Colin Walls has been working in the electronics industry for more than thirty years, spending a significant amount of time on embedded software. He is now an embedded software engineer in Mentor Embedded (a division of Mentor Graphics). Colin Walls often speaks at conferences and seminars, author of numerous technical articles and two books on embedded software. Lives in the UK.
Colin's professional
blog , e-mail: colin_walls@mentor.com.