Toda la verdad sobre RTOS. Artículo # 17. Grupos de banderas de eventos: Introducción y servicios básicos



Grupos de banderas de eventos ya se mencionaron anteriormente en uno de los artículos anteriores (# 5). En Nucleus SE, son similares a las señales, pero son más flexibles. Proporcionan una forma flexible y de bajo costo para transferir mensajes simples entre tareas.


Artículos anteriores de la serie:
Artículo # 16. Señales
Artículo # 15. Particiones de memoria: servicios y estructuras de datos
Artículo # 14. Secciones de memoria: introducción y servicios básicos.
Artículo 13. Estructuras de datos de tareas y llamadas de API no compatibles
Artículo # 12. Servicios para trabajar con tareas.
Artículo # 11. Tareas: configuración e introducción a la API
Artículo # 10. Programador: funciones avanzadas y preservación del contexto
Artículo # 9. Programador: implementación
Artículo # 8. Nucleus SE: diseño interno y despliegue
Artículo # 7. Núcleo SE: Introducción
Artículo # 6. Otros servicios RTOS
Artículo # 5. Interacción de tareas y sincronización
Artículo # 4. Tareas, cambio de contexto e interrupciones
Artículo # 3. Tareas y planificación
Artículo # 2. RTOS: estructura y modo en tiempo real
Artículo # 1. RTOS: introducción.


Usar banderas de eventos


En Nucleus SE, las banderas de eventos se definen durante la fase de construcción. El número máximo de grupos de indicadores de eventos en la aplicación es 16. Si los grupos de indicadores de eventos no están definidos, el código relacionado con las estructuras de datos y las llamadas de servicio de los grupos de indicadores de eventos no se incluirán en la aplicación.

Grupo de banderas de eventos: un conjunto de banderas de ocho bits, cuyo acceso está regulado para que varias tareas puedan usar una bandera de manera segura. Una tarea puede establecer o borrar cualquier combinación de banderas de eventos. Otra tarea es leer un grupo de banderas en cualquier momento, y también puede esperar una cierta secuencia de banderas (por sondeo o con una pausa).

Configurar grupos de banderas de eventos


Número de grupos de banderas de eventos


Como con la mayoría de los objetos de Nucleus SE, la configuración de los grupos de indicadores de eventos se especifica mediante las directivas #define en nuse_config.h El parámetro principal es NUSE_EVENT_GROUP_NUMBER , que determina cuántos grupos de banderas de eventos se definirán en la aplicación. De manera predeterminada, este parámetro se establece en 0 (es decir, no se utilizan grupos de indicadores de evento) y puede tener cualquier valor hasta 16. Un valor incorrecto generará un error de compilación, que se generará al ingresar nuse_config_check.h (está habilitado por nuse_config.c , lo que significa que se compila con este módulo), como resultado, la directiva #error funcionará. La selección de un valor distinto de cero sirve como el activador principal de los grupos de banderas de eventos. Este parámetro se utiliza al definir estructuras de datos y su tamaño depende de su valor (más información sobre esto en los siguientes artículos). Además, un valor distinto de cero activa la configuración de la API.

Activar llamadas API


Cada función API (llamada de utilidad) en Nucleus SE se activa mediante la directiva #define en nuse_config.h . Para grupos de banderas de eventos, estos incluyen:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT

Por defecto, están configurados en FALSO , deshabilitando así cada llamada de servicio y bloqueando la inclusión de código que los implementa. Para configurar grupos de indicadores de eventos, debe seleccionar las llamadas API necesarias y establecer las directivas correspondientes en TRUE .

Lo siguiente es un extracto del archivo predeterminado nuse_config.h.

 #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 */ 

Una función de API activada si no hay grupos de indicadores de eventos en la aplicación dará lugar a un error de compilación (excepto NUSE_Event_Group_Count () , que siempre está habilitado). Si su código usa una llamada API que no se ha activado, se producirá un error de diseño porque el código de implementación no se incluyó en la aplicación.

Llamada de evento Llamadas de utilidad


Nucleus RTOS admite siete llamadas de utilidad que proporcionan la siguiente funcionalidad:

  • Establecer banderas de eventos. Nucleus SE se implementa en la función NUSE_Event_Group_Set () .
  • Lectura de banderas de eventos. En Nucleus SE, implementado en NUSE_Event_Group_Retrieve () .
  • Proporcionar información sobre un grupo específico de banderas de eventos. En Nucleus SE, implementado en NUSE_Event_Group_Information () .
  • Devuelve el número de grupos de marcadores de eventos configurados actualmente en la aplicación. En Nucleus SE, implementado en NUSE_Event_Group_Count () .
  • Agregar un nuevo grupo de banderas de eventos a la aplicación. Nucleus SE no está implementado.
  • Eliminar un grupo de banderas de eventos de la aplicación. Nucleus SE no está implementado.
  • Devolver punteros a todos los grupos de banderas de eventos en la aplicación. Nucleus SE no está implementado.

La implementación de cada una de estas llamadas generales se analiza en detalle a continuación.

Vale la pena señalar que no hay función de reinicio en Nucleus RTOS o Nucleus SE. Esto se hace intencionalmente. La función de reinicio implica la prevalencia del estado especial de las banderas. Para grupos de banderas de eventos, el único estado "especial" es restablecer todas las banderas, lo que se puede hacer usando NUSE_Event_Group_Set () .

Llamadas de servicio para configurar y leer grupos de banderas de eventos


Las operaciones fundamentales que se pueden realizar en un grupo de indicadores de evento son establecer el valor de uno o más indicadores, así como leer los valores de indicadores actuales. Nucleus RTOS y Nucleus SE proporcionan cuatro llamadas API básicas para estas operaciones.

Dado que las banderas de eventos son bits, se visualizan mejor como números binarios. Dado que el estándar C históricamente no ha admitido la representación de constantes binarias (solo octales y hexadecimales), Nucleus SE tiene un útil archivo de encabezado nuse_binary.h , que contiene caracteres #definidos como b01010101 para todos los 256 valores de 8 bits.

Establecer banderas de eventos


La llamada a la utilidad de la API Nucleus RTOS para marcar es muy flexible y le permite establecer y borrar los valores de marca mediante operaciones AND y OR . Nucleus SE proporciona una funcionalidad similar, pero la pausa de tareas es opcional.

Llamada para establecer banderas en Nucleus RTOS
Prototipo de llamada de servicio:

ESTADO NU_Set_Events (grupo NU_EVENT_GROUP *, banderas de evento NO FIRMADAS, operación OPTION);

Parámetros:

grupo : un puntero a un bloque de control proporcionado por el usuario para un grupo de indicadores de evento;
event_flags : valor de la máscara de bits del grupo de banderas;
operación : la operación a realizar, NU_OR (para establecer banderas) o NU_AND (para borrar banderas).

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_GROUP : puntero no válido a un grupo de banderas de eventos;
NU_INVALID_OPERATION : la operación especificada es diferente de NU_OR y NU_AND .

Llamada para establecer banderas en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Event_Group_Set (grupo NUSE_EVENT_GROUP, U8 event_flags, operación OPTION);

Parámetros:

grupo : el índice (ID) del grupo de eventos cuyas banderas se establecen / borran;
event_flags - valor del bit maxi de un grupo de banderas;
operación : la operación a realizar, NUSE_OR (para establecer banderas) o NUSE_AND (para borrar banderas).

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_GROUP : índice no válido de un grupo de banderas de eventos;
NUSE_INVALID_OPERATION : la operación especificada es diferente de NUSE_OR y NUSE_AND .

Implementación de la instalación de banderas de eventos en Nucleus SE
El código inicial de la función API NUSE_Event_Group_Set () es general (después de verificar los parámetros), independientemente de si la API admite llamadas de bloqueo (suspender tareas) o no. La lógica es bastante 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; } 

La máscara de bits event_flags se superpone (utilizando la operación AND u OR ) en el valor del grupo seleccionado de banderas de eventos.

El código restante se habilita solo cuando se activa el bloqueo de tareas:

 #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 #endif NUSE_CS_Exit(); return NUSE_SUCCESS; 

Si alguna tarea está en pausa (para leer) de este grupo de banderas, se reanudará. Cuando tienen la oportunidad de continuar la ejecución (depende del planificador), pueden determinar si se cumplen o no las condiciones para su reanudación (consulte la lectura de las banderas de eventos).

Lectura de banderas de eventos


Las llamadas de la utilidad Nucleus RTOS API para la lectura son muy flexibles y le permiten pausar tareas indefinidamente o con un tiempo de espera específico si la operación no se puede realizar de inmediato (por ejemplo, si intenta leer una secuencia específica de indicadores de evento que no representa el estado actual). Nucleus SE proporciona las mismas características, solo la pausa de tareas es opcional y no se implementa el tiempo de espera.

Flags Challenge en Nucleus RTOS
Prototipo de llamada de servicio:

ESTADO NU_Retrieve_Events (grupo NU_EVENT_GROUP *, EVENTOS solicitados NO FIRMADOS, operación OPCIÓN, NO FIRMADOS * eventos recuperados, suspensión NO FIRMADA);

Parámetros:

grupo : un puntero a un bloque de control proporcionado por el usuario para un grupo de indicadores de evento;
request_events : una máscara de bits que define los indicadores que se leerán;
operación : hay cuatro operaciones disponibles: NU_AND , NU_AND_CONSUME , NU_OR y NU_OR_CONSUME . Las operaciones NU_AND y NU_AND_CONSUME indican que se requieren todos los indicadores solicitados. Las operaciones NU_OR y NU_OR_CONSUME indican que uno o más de los indicadores solicitados son suficientes. El parámetro CONSUME borra automáticamente los indicadores existentes después de una solicitud exitosa;
retrieved_events : puntero de almacenamiento para los valores de los indicadores de evento de lectura;
suspender : especificación para pausar tareas; puede tomar los valores NU_NO_SUSPEND o NU_SUSPEND , o el valor de tiempo de espera en tics del temporizador del sistema (de 1 a 4,294,967,293).

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_NOT_PRESENT : la operación especificada no devolvió eventos (ni un solo evento en el caso de NU_OR y no todos los eventos en el caso de NU_AND);
NU_INVALID_GROUP : puntero no válido a un grupo de banderas de eventos;
NU_INVALID_OPERATION : la operación especificada fue incorrecta;
NU_INVALID_POINTER - puntero nulo a la tienda de banderas de eventos (NULL);
NU_INVALID_SUSPEND : intenta pausar desde un hilo no relacionado con la tarea;
NU_TIMEOUT : la combinación requerida de indicadores de evento no se estableció incluso después del tiempo de espera especificado;
NU_GROUP_DELETED : el grupo de indicadores de evento se eliminó mientras se suspendió la tarea.

Flags Challenge en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Event_Group_Retrieve (grupo NUSE_EVENT_GROUP, eventos solicitados U8, operación OPTION, U8 * eventos_recuperados, suspensión U8);

Parámetros:

grupo - índice (ID) del grupo de lectura de banderas de eventos;
request_events : una máscara de bits que define los indicadores que se leerán;
operación : una especificación que indica el número de indicadores necesarios: NUSE OR (algunos indicadores) o NUSE AND (todos los indicadores);
retrieved_events : un puntero a la tienda para los valores reales de los indicadores de evento de lectura (con la operación NUSE_AND, esto será lo mismo que se pasó en el parámetro request_events );
suspender : especificación para pausar una tarea; puede tomar los valores NUSE_NO_SUSPEND o NUSE_SUSPEND .

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_NOT_PRESENT : la operación especificada no devolvió eventos (ni un solo evento en el caso de NUSE_OR y no todos los eventos en el caso de NUSE_AND );
NUSE_INVALID_GROUP : índice no válido de un grupo de banderas de eventos;
NUSE_INVALID_OPERATION : la operación especificada es diferente de NUSE_OR o NUSE_AND ;
NUSE_INVALID_POINTER : un puntero nulo al almacén de indicadores de evento de lectura ( NULL );
NUSE_INVALID_SUSPEND : un intento de pausa desde un flujo que no es de tarea o cuando el soporte para bloquear llamadas API está deshabilitado.

Implementación de lectura de banderas de eventos en Nucleus SE
La versión del código de función API NUSE_Event_Group_Retrieve () (después de verificar los parámetros) se selecciona durante la compilación condicional dependiendo de si el soporte para las llamadas API para bloquear (suspender) tareas está activado o no. Consideremos estas dos opciones por separado.

Si el bloqueo está desactivado, el código completo para esta llamada a la API se verá así:

 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; } } 

Las banderas de eventos requeridas se seleccionan del grupo de banderas de eventos especificado. El valor se compara con los eventos requeridos, teniendo en cuenta la operación AND / OR , así como el resultado devuelto y los valores inmediatos de los indicadores solicitados.

Si se activa el bloqueo de tareas, el código se vuelve más complejo:

 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); 

El código se coloca en un bucle do ... while , que funciona mientras el parámetro de suspensión es NUSE_SUSPEND .

Los indicadores de evento solicitados se leen como si se hubieran llamado sin bloqueo. Si la lectura no es exitosa y el parámetro de suspensión es NUSE_NO_SUSPEND , la llamada API se establece en NUSE_NOT_PRESENT . Si el parámetro de suspensión se estableció en NUSE_SUSPEND , la tarea se detiene. Al regresar (cuando se reanuda la tarea), si el valor de retorno es NUSE_SUCCESS , lo que indica que la tarea se reanudó porque los indicadores de evento en este grupo se establecieron o borraron, el ciclo comienza desde el principio, los indicadores se leen y comprueban. Dado que no hay una función API para restablecer los grupos de marcadores de eventos, esta es la única razón por la que la tarea se reanuda, pero el proceso de verificación NUSE_Task_Blocking_Return [] se ha dejado en el sistema por la compatibilidad del control de bloqueo con otros tipos de objetos.

El siguiente artículo describirá llamadas API adicionales asociadas con grupos de indicadores de eventos, así como sus estructuras de datos.

Sobre el autor: Colin Walls ha trabajado en la industria electrónica durante más de treinta años, dedicando la mayor parte de su tiempo al firmware. Ahora es ingeniero de firmware en Mentor Embedded (una división de Mentor Graphics). Colin Walls a menudo habla en conferencias y seminarios, autor de numerosos artículos técnicos y dos libros sobre firmware. Vive en el Reino Unido. Blog profesional de Colin , correo electrónico: colin_walls@mentor.com.

Source: https://habr.com/ru/post/es428131/


All Articles