Toda la verdad sobre RTOS. Artículo # 24. Colas: servicios auxiliares y estructuras de datos.



En este artículo, continuaremos considerando las colas.

Servicios de colas secundarias


Nucleus RTOS tiene cuatro llamadas API que proporcionan funciones auxiliares relacionadas con las colas: restablecer una cola, recibir información de la cola, obtener el número de colas en una aplicación y obtener punteros a todas las colas en una aplicación. Las primeras tres funciones se implementan en Nucleus SE.

Artículos anteriores de la serie:

Artículo 23. Colas: introducción y servicios básicos.
Artículo # 22. Buzones: servicios auxiliares y estructuras de datos
Artículo # 21. Buzones: Introducción y servicios básicos
Artículo # 20. Semáforos: servicios auxiliares y estructuras de datos
Artículo # 19. Semáforos: introducción y servicios básicos.
Artículo # 18. Grupos de banderas de eventos: servicios auxiliares y estructuras de datos
Artículo # 17. Grupos de banderas de eventos: Introducción y servicios básicos
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.

Restablecer cola


Esta llamada a la API restablece la cola a su estado original no utilizado. Se perderán todos los mensajes almacenados en la cola. Cualquier tarea pausada en la cola se reanudará con el código de retorno NUSE_QUEUE_WAS_RESET .

Llamada de restablecimiento de cola en Nucleus RTOS
Prototipo de llamada de servicio:
ESTADO NU_Reset_Queue (cola NU_QUEUE *);

Parámetros:
cola : un puntero a un bloque de control de cola proporcionado por el usuario.

Valor de retorno:
NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_QUEUE : puntero de cola no válido.

Llamada de restablecimiento de cola en Nucleus SE
Esta llamada de utilidad admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:
ESTADO NUSE_Queue_Reset (cola NUSE_QUEUE);

Parámetros:
cola - índice (ID) de la cola volcada.

Valor de retorno:
NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_QUEUE : índice de cola no válido.

Implementación de restablecimiento de cola en Nucleus SE
El código de la función NUSE_Queue_Reset (después de verificar los parámetros) es bastante simple. Los índices de la cabecera y la cola de la cola, así como el contador de mensajes en la cola, tienen asignado un valor cero.

Si se activa el bloqueo de tareas, el código adicional es responsable de restaurar las tareas suspendidas:

while (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this queue */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { NUSE_Task_Blocking_Return[index] = NUSE_QUEUE_WAS_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Queue_Blocking_Count[queue]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif 

A cada tarea en pausa en la cola se le asigna un estado "listo" con un código de retorno de NUSE_QUEUE_WAS_RESET . Una vez completado este proceso, si se utiliza el planificador prioritario, se llama a la función NUSE_Reschedule () , ya que una o más tareas con alta prioridad pueden estar listas para ejecutarse.

Obteniendo información de la cola


Esta llamada de servicio proporciona información de la cola. La implementación de esta llamada en Nucleus SE difiere de Nucleus RTOS en que devuelve menos información, ya que la denominación de objetos, la longitud variable del mensaje y el orden de pausa de la tarea no son compatibles, y el bloqueo de la tarea puede desactivarse.

Convocatoria de información de cola en Nucleus RTOS
Prototipo de llamada de servicio:

ESTADO NU_Queue_Information (NU_QUEUE * queue, CHAR * name, VOID ** start_address, UNSIGNED * queue_size, UNSIGNED * available, UNSIGNED * messages, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * first_task_k_

Parámetros:

cola : un puntero a un bloque de control de cola proporcionado por el usuario;
nombre : puntero a la región de 8 caracteres para el nombre del mensaje en la cola;
start_address : un puntero a un puntero en el que se escribirá la dirección del comienzo del área de datos de la cola;
queue_size : un puntero a una variable para almacenar el número total de elementos SIN FIRMAR en la cola;
disponible : un puntero a una variable para almacenar el número de elementos SIN FIRMAR disponibles en la cola;
mensajes: un puntero a una variable para almacenar el número actual de mensajes en la cola;
message_type : un puntero a una variable para almacenar el tipo de mensajes admitidos por la cola. Los valores válidos son NU_FIXED_SIZE y NU_VARIABLE ;
message_size : un puntero a una variable para almacenar el número de elementos de datos SIN FIRMAR en cada mensaje de la cola. Si la cola admite mensajes de longitud variable, este número indica la longitud máxima del mensaje;
suspend_type : un puntero a una variable para almacenar el tipo de suspensión de tareas. Los valores válidos son NU_FIFO y NU_PRIORITY ;
task_waiting : un puntero a una variable para almacenar el número de tareas suspendidas en esta cola;
first_task : puntero al puntero de la tarea, en el que se coloca el puntero de la primera tarea suspendida.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_QUEUE : puntero de cola no válido.

Llame para obtener información sobre la cola en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Queue_Information (cola NUSE_QUEUE, ADDR * start_address, U8 * queue_size, U8 * disponible, U8 * mensajes, U8 * task_waiting, NUSE_TASK * first_task);

Parámetros:

cola - índice de la cola sobre la que se solicita información;
start_address : un puntero a una variable de tipo ADDR , en la que se almacenará la dirección del comienzo del área de datos de la cola;
queue_size : un puntero a una variable de tipo U8 , que almacenará el número total de mensajes que pueden caber en la cola;
disponible : un puntero a una variable de tipo U8 , que almacenará el número de lugares libres en la cola;
mensajes : un puntero a una variable de tipo U8 , que almacenará el número actual de mensajes en la cola;
task_waiting : un puntero a una variable en la que se almacenará el número de tareas suspendidas en esta cola (no se devuelve nada si el bloqueo de tareas está desactivado);
first_task : un puntero a una variable del tipo NUSE_TASK en la que se almacenará el índice de la primera tarea suspendida (no se devuelve nada si el bloqueo de la tarea está desactivado).

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_QUEUE : índice de cola no válido;
NUSE_INVALID_POINTER : uno o más parámetros de puntero son incorrectos.

Implementación de visualización de información de cola en Nucleus SE

Implementar esta llamada a la API es bastante simple:

 *start_address = NUSE_Queue_Data[queue]; *queue_size = NUSE_Queue_Size[queue]; *available = NUSE_Queue_Size[queue] - NUSE_Queue_Items[queue]; *messages = NUSE_Queue_Items[queue]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Queue_Blocking_Count[queue]; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif 

La función devuelve el estado de la cola. Luego, si se activa el bloqueo de tareas, se devuelve el número de tareas pendientes y el índice de la primera de ellas (de lo contrario, ambos parámetros se establecen en 0).

Obtener el número de colas


Esta llamada de utilidad devuelve el número de colas configuradas en la aplicación. En Nucleus RTOS, su número puede cambiar con el tiempo, y el valor de retorno indicará el número actual de colas. En Nucleus SE, el valor de retorno se establece durante la fase de construcción y no se puede cambiar.

Llamar al contador de colas en Nucleus RTOS
Prototipo de llamada de servicio:
NU_Nuevo_Establecido_Cosas (ANULADO);

Parámetros:
Están ausentes

Valor de retorno:
El número de colas creadas en el sistema.

Llamar al contador de colas en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:
U8 NUSE_Queue_Count (nulo);

Parámetros:
Están ausentes

Valor de retorno:
El número de colas configuradas en la aplicación.

Implementación del contador de cola en Nucleus SE
La implementación de esta llamada a la API es muy simple: se devuelve el valor del símbolo #define NUSE_QUEUE_NUMBER .

Estructuras de datos


Las colas usan cinco o seis estructuras de datos (que están en RAM o ROM), que son conjuntos de tablas (como otros objetos de Nucleus SE), cuyo número y tamaño corresponden al número de colas en la aplicación y los parámetros seleccionados.

Datos del kernel en RAM


Estos datos tienen la siguiente estructura:

NUSE_Queue_Head [] es una matriz de punteros de tipo U8 , tiene una entrada para cada cola configurada y apunta al encabezado de la cola de mensajes. Se utiliza como índice de dirección en NUSE_Queue_Data [] (ver más abajo);
NUSE_Queue_Tail [] es una matriz de tipo U8 , tiene una entrada para cada cola configurada en la aplicación y apunta a la cola de la cola de mensajes. Se utiliza como índice de dirección en NUSE_Queue_Data [] (ver más abajo);
NUSE_Queue_Items [] es una matriz de tipo U8 , tiene una entrada para cada cola configurada y es un contador de mensajes en la cola. Estos datos pueden considerarse redundantes, ya que estos valores pueden obtenerse a través de los índices del principio y el final de la cola, sin embargo, almacenar el contador simplifica el código;
NUSE_Queue_Blocking_Count [] : esta matriz de tipo U8 contiene contadores del número de tareas suspendidas en cada cola. Esta matriz solo se crea si el soporte de bloqueo de tareas está activado.

Estas estructuras de datos se inicializan a ceros mediante la función NUSE_Init_Queue () cuando se inicia Nucleus SE. Esto es lógico, ya que todas las colas se crean vacías (no se usan).

Las siguientes son las definiciones de estas estructuras en el archivo nuse_init.c :

 RAM U8 NUSE_Queue_Head[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Tail[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Items[NUSE_QUEUE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Queue_Blocking_Count[NUSE_QUEUE_NUMBER]; #endif 

Datos de usuario RAM


El usuario es responsable de proporcionar un área de RAM para almacenar cada cola. El tamaño de esta área debe contener una matriz de tipo ADDR , en el que cada registro corresponde a un mensaje en la cola

Datos ROM


Estos datos tienen la siguiente estructura:

NUSE_Queue_Data [] : una matriz de tipo ADDR , tiene una entrada para cada cola configurada y apunta al área de datos de la cola (ver. Datos de RAM del usuario);
NUSE_Queue_Size [] : una matriz de tipo U8 , tiene una entrada para cada cola configurada y muestra el número máximo de mensajes que puede recibir cada cola.

Estas estructuras de datos se declaran e inicializan (estáticamente) en el archivo nuse_config.c :

 ROM ADDR *NUSE_Queue_Data[NUSE_QUEUE_NUMBER] = { /* addresses of queue data areas ------ */ }; ROM U8 NUSE_Queue_Size[NUSE_QUEUE_NUMBER] = { /* queue sizes ------ */ }; 

La cantidad de memoria para las colas.


Como todos los objetos del núcleo de Nucleus SE, la cantidad de memoria necesaria para las colas es fácilmente predecible.

La cantidad de datos en ROM (en bytes) para todas las colas en la aplicación se puede calcular de la siguiente manera:
NUSE_QUEUE_NUMBER * (sizeof (ADDR) + 1)

La cantidad de datos del kernel en RAM (en bytes) para todas las colas en la aplicación con el bloqueo de tareas activado se calcula de la siguiente manera:
NUSE_QUEUE_NUMBER * 3

Si el bloqueo está desactivado:
NUSE_QUEUE_NUMBER * 4

La cantidad de datos de usuario en RAM (en bytes) para la cola con el índice de cola :
NUSE_Queue_Size [cola] * sizeof (ADDR)

Llamadas API no realizadas


Cuatro llamadas API que se pueden encontrar en Nucleus RTOS no se implementan en Nucleus SE:

Creación de cola


Esta llamada a la API crea una cola; en Nucleus SE, esto no es necesario, ya que las colas se crean estáticamente.

Prototipo de llamada de servicio:
ESTADO NU_Create_Queue (NU_QUEUE * queue, char * name, VOID * start_address, UNSIGNED queue_size, OPTION message_size, UNSIGNED message_size, OPTION suspend_type);

Parámetros:

cola : un puntero a una unidad de control proporcionada por el usuario; se usa para administrar colas en otras llamadas API;
nombre : un puntero a un nombre de cola de 7 caracteres con un byte de terminación nulo;
start_address : dirección del comienzo de la cola;
message_type : tipo de mensaje admitido por la cola. Puede tomar los valores NU_FIXED_SIZE o NU_VARIABLE_SIZE ;
message_size : si la cola admite mensajes de una longitud fija, este parámetro establece la longitud exacta de cada mensaje; de ​​lo contrario, si la cola admite mensajes de longitud variable, este valor es la longitud máxima del mensaje;
suspend_type : determina el tipo de tareas de suspensión en la cola. Puede tomar los valores NU_FIFO y NU_PRIORITY , que significan el principio de FIFO (Primero en entrar , primero en salir) o el principio de prioridad de suspensión de tareas, respectivamente.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_QUEUE : puntero nulo al bloque de control de cola ( NULL ), o el puntero ya está en uso;
NU_INVALID_MEMORY : área de memoria no válida especificada en start_address ;
NU_INVALID_MESSAGE : parámetro de tipo de mensaje no válido;
NU_INVALID_SIZE : la cola no admite mensajes de esta longitud, o el tamaño de la cola y / o la longitud del mensaje es 0;
NU_INVALID_SUSPEND : parámetro inválido suspend_type .

Eliminar cola


Esta llamada a la API elimina la cola creada anteriormente. Nucleus SE no necesita esto porque las colas se crean de forma estática y no se pueden eliminar.

Prototipo de llamada de servicio:
ESTADO NU_Delete_Queue (cola NU_QUEUE *);

Parámetros:
cola : un puntero a un bloque de control de cola.

Valor de retorno:
NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_QUEUE : puntero de cola no válido.

Punteros de cola


Esta llamada a la API crea una lista secuencial de punteros a todas las colas en el sistema. Nucleus SE no necesita esto porque las colas se identifican usando un índice simple, no un puntero.

Prototipo de llamada de servicio:
NU_Queue_Pointers SIN FIRMAR (NU_QUEUE ** pointer_list, UNSIGNED maximum_pointers);

Parámetros:
pointer_list : puntero a una matriz de punteros NU_QUEUE . Esta matriz se llenará con punteros a las colas creadas en el sistema;
maximum_pointers : el número máximo de punteros en la matriz.

Valor de retorno:
El número de punteros NU_QUEUE en la matriz.

En cola (Broadcast to Queue)


Esta llamada a la API pasa el mensaje a todas las tareas suspendidas en la cola que están esperando mensajes de la cola especificada. Esta característica no se implementa en Nucleus SE ya que agrega redundancia.

Prototipo de llamada de servicio:
ESTADO NU_Broadcast_To_Queue (NU_QUEUE * queue, VOID * message, UNSIGNED size, UNSIGNED suspend);

Parámetros:

cola - un puntero a un bloque de control de cola;
mensaje : puntero al mensaje transmitido;
tamaño : el número de elementos NO FIRMADOS en el mensaje. Si la cola admite mensajes de longitud variable, este parámetro debe ser igual o menor que la longitud del mensaje admitida por la cola. Si la cola admite mensajes de una longitud fija, este parámetro debe ser igual a la longitud del mensaje admitido por la cola;
suspen : indica si se suspende la tarea de llamada si la cola ya está llena. Puede ser NU_NO_SUSPEND , NU_SUSPEND o un valor de tiempo de espera.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_QUEUE : puntero de cola no válido;
NU_INVALID_POINTER : puntero nulo a un mensaje ( NULL );
NU_INVALID_SIZE : la longitud del mensaje especificado no es compatible con la longitud especificada al crear la cola;
NU_INVALID_SUSPEND : intenta pausar una tarea desde un hilo no asociado con la tarea;
NU_QUEUE_FULL : no hay suficiente espacio en la cola para el mensaje;
NU_TIMEOUT : la cola sigue llena después de que expira el tiempo de espera;
NU_QUEUE_DELETED : la cola se eliminó mientras se suspendió la tarea;
NU_QUEUE_RESET : la cola se restableció mientras se suspendía la tarea.

Nucleus RTOS Compatible


Al igual que con todos los demás objetos de Nucleus SE, mi objetivo era maximizar la compatibilidad del código de la aplicación con Nucleus RTOS. Las colas no son una excepción y, desde el punto de vista del usuario, se implementan de la misma manera que en Nucleus RTOS. También hay una cierta incompatibilidad, que consideré aceptable, dado que, como resultado, el código será más comprensible y más eficiente en términos de la cantidad de memoria requerida. De lo contrario, las llamadas a la API de Nucleus RTOS se pueden transferir casi directamente a Nucleus SE.

Identificadores de objetos


En Nucleus RTOS, todos los objetos se describen mediante una estructura de datos (unidades de control) que tiene un tipo de datos específico. Un puntero a esta unidad de control sirve como un identificador para la cola. Decidí que en Nucleus SE, se necesita un enfoque diferente para el uso eficiente de la memoria: todos los objetos del núcleo se describen mediante un conjunto de tablas en RAM y / o ROM. El tamaño de estas tablas está determinado por el número de objetos configurados de cada tipo. El identificador de un objeto particular es el índice en esta tabla. Así que definí NUSE_QUEUE como el equivalente de U8 , una variable (no un puntero) de este tipo sirve como identificador de la cola. Esta ligera incompatibilidad es fácil de manejar si el código se transfiere de Nucleus SE a Nucleus RTOS y viceversa. Por lo general, no se realizan operaciones en identificadores de objetos que no sean mover y almacenar.

Nucleus RTOS también admite nombres de colas. Estos nombres se usan solo para la depuración. Los excluí de Nucleus SE para ahorrar memoria.

Tamaño y tipo de mensaje


En Nucleus RTOS, se puede configurar una cola para procesar mensajes que consisten en cualquier número de elementos sin firmar . En Nucleus SE, las colas se simplifican y solo admiten mensajes de tipo ADDR individuales. Los canales de datos de Nucleus SE son un poco más flexibles y pueden ser una alternativa útil a las colas en algunos casos. Los canales serán cubiertos en los próximos dos artículos de esta serie.

Nucleus SE también admite colas de mensajes de longitud variable, que especifican solo la longitud máxima del mensaje durante la creación. Nucleus SE no admite longitudes de mensaje variables

Tamaño de cola


En Nucleus SE, el número máximo de mensajes en una cola es 256, ya que todas las variables y constantes son del tipo U8 . Nucleus RTOS no tiene tales limitaciones.

Llamadas API no realizadas


Nucleus RTOS admite diez llamadas de gestión de colas. De estos, cuatro no están implementados en Nucleus SE. Los detalles de estas llamadas, así como los motivos de tal decisión, se pueden encontrar en este artículo anterior, en la sección "Llamadas API no realizadas".

El próximo artículo discutirá los canales de transmisión 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/es432804/


All Articles