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



En este artículo, continuaremos considerando los canales de transmisión de datos.

Servicios de soporte de canales


Nucleus RTOS tiene cuatro llamadas API que proporcionan funciones auxiliares relacionadas con los canales: restablecer un canal, recibir información del canal, obtener el número de canales en una aplicación y obtener punteros a todos los canales en una aplicación. Las primeras tres funciones se implementan en Nucleus SE.

Artículos anteriores de la serie:

Artículo # 25. Canales de datos: introducción y servicios básicos
Artículo # 24. Colas: servicios auxiliares y estructuras de datos.
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.

Restablecimiento de canal


Esta llamada a la API restablece el canal a su estado original no utilizado. Cualquier mensaje almacenado en él se perderá. Cualquier tarea suspendida en el canal se reanuda con el código de retorno NUSE_PIPE_WAS_RESET .

Llamada de restablecimiento de canal en Nucleus RTOS

Prototipo de llamada de servicio:

ESTADO NU_Reset_Pipe (tubería NU_PIPE *);

Parámetros:

pipe : un puntero a un bloque de control de canal definido por el usuario.

Valor de retorno:

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

Desafío de restablecimiento de canal en Nucleus SE

Esta llamada de servicio API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Pipe_Reset (tubería NUSE_PIPE);

Parámetros:

pipe es el índice (ID) de la tubería que se cae.

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_PIPE : índice de canal no válido.

Implementación de restablecimiento de canal en Nucleus SE

El código para la función NUSE_Pipe_Reset () (después de verificar los parámetros) es bastante simple. Los índices de inicio y finalización del canal, así como el contador de mensajes en el canal, se establecen en 0.

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

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

A cada tarea suspendida en el canal se le asigna el estado "listo" con el código de retorno NUSE_PIPE_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 su ejecución.

Información del canal


Esta llamada de servicio devuelve información del canal. La implementación de esta llamada en Nucleus SE difiere de Nucleus RTOS en que devuelve menos información. Esto se debe a que Nucleus SE no admite los nombres de objetos, los mensajes de longitud variable y el orden de pausa de la tarea, y la pausa de la tarea se puede deshabilitar.

Llame para obtener información del canal en Nucleus RTOS
Prototipo de llamada de servicio:

ESTADO NU_Pipe_Information (NU_PIPE * pipe, CHAR * name, VOID ** start_address, UNSIGNED * pipe_size, UNSIGNED * available, UNSIGNED * messages, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * task_waask

Parámetros:

pipe - puntero al bloque de control de canal proporcionado por el usuario;
nombre : puntero al área de 8 caracteres para el nombre del mensaje del canal;
start_address : un puntero a un puntero en el que se escribirá la dirección del comienzo del área de datos del canal;
pipe_size : un puntero a una variable para almacenar el número total de bytes en el canal;
disponible : apunta a una variable para almacenar el número de bytes disponibles en el canal;
mensajes : un puntero a una variable para almacenar el número de mensajes en el canal;
message_type : un puntero a una variable para almacenar el tipo de mensaje admitido por el canal. Puede tomar los valores NU_FIXED_SIZE y NU_VARIABLE_SIZE ;
message_size : puntero a una variable para almacenar el número de bytes en cada mensaje de canal. Si el canal admite mensajes de longitud variable, este número será el tamaño máximo del mensaje;
suspend_type : puntero a una variable para almacenar el tipo de tarea de suspensión. Puede tomar los valores NU_FIFO y NU_PRIORITY ;
task_waiting : un puntero a una variable para almacenar el número de tareas suspendidas en este canal;
first_task : un puntero a un puntero a la primera tarea en pausa.

Valor de retorno:

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

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

Prototipo de llamada de servicio:

STATUS NUSE_Pipe_Information (tubería NUSE_PIPE, ADDR * start_address, U8 * pipe_size, U8 * disponible, U8 * messages, U8 * message_size, U8 * tareas_waiting, NUSE_TASK * first_task);

Parámetros:

pipe - índice del canal, información sobre la cual se solicita;
start_address : puntero a una variable de tipo ADDR para almacenar la dirección del comienzo del área de datos del canal;
pipe_size : un puntero a una variable de tipo U8 para almacenar el número total de mensajes que puede recibir el canal;
disponible : un puntero a una variable de tipo U8 para almacenar la cantidad de mensajes para los que queda espacio libre en el canal;
mensajes : un puntero a una variable de tipo U8 para almacenar el número actual de mensajes en el canal;
message_size : puntero a una variable de tipo U8 para almacenar el tamaño de los mensajes procesados ​​por este canal;
task_waiting : un puntero a una variable para almacenar el número de tareas suspendidas en este canal (no se devuelve nada si la suspensión de tareas está desactivada);
first_task : un puntero a una variable del tipo NUSE_TASK , que tomará el índice de la primera tarea suspendida (no se devuelve nada si la suspensión de la tarea está desactivada).

Valor de retorno:

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

Implementación de información del canal en Nucleus SE

Implementar esta llamada a la API es bastante simple:

 *start_address = NUSE_Pipe_Data[pipe]; *pipe_size = NUSE_Pipe_Size[pipe]; *available = NUSE_Pipe_Size[pipe] - NUSE_Pipe_Items[pipe]; *messages = NUSE_Pipe_Items[pipe]; *message_size = NUSE_Pipe_Message_Size[pipe]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Pipe_Blocking_Count[pipe]; if (NUSE_Pipe_Blocking_Count[pipe] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_PIPE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == pipe)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif 

La función devuelve el estado del canal. Luego, si se activan los bloqueos de tareas, se devuelve el número de tareas pendientes y el índice de la primera de ellas (de lo contrario, estos dos parámetros se establecen en 0).

Obtener el número de canales


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

Solicite un contador de canales en Nucleus RTOS
Prototipo de llamada de servicio:

NO FIRMADO NU_Established_Pipes (VOID);

Parámetros:
Están ausentes

Valor de retorno:
El número de canales creados en el sistema.

Llame para obtener un contador de canales en Nucleus SE
Esta llamada de utilidad admite la funcionalidad principal de la API Nucleus RTOS

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

Parámetros:
Están ausentes

Valor de retorno:
El número de canales configurados en la aplicación.

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

Estructuras de datos


Los canales usan seis o siete estructuras de datos (que están en RAM o en ROM), que son (como otros objetos de Nucleus SE) un conjunto de tablas, cuyo tamaño y número corresponde al número de canales configurados y sus parámetros.

Recomiendo encarecidamente que el código de la aplicación no utilice el acceso directo a estas estructuras de datos, sino que se refiera a ellas a través de las funciones API proporcionadas. Esto evitará la incompatibilidad con futuras versiones de Nucleus SE y los efectos secundarios no deseados, además de simplificar la transferencia de aplicaciones a Nucleus RTOS. La siguiente es una descripción detallada de las estructuras de datos para simplificar la comprensión de la llamada de servicio y el código de depuración.

Datos del kernel en RAM


Estos datos tienen la siguiente estructura:

NUSE_Pipe_Head [] es una matriz de punteros del tipo U8 , que tiene una entrada para cada canal configurado e indica el comienzo del canal del mensaje. Se utiliza como índice de dirección en NUSE_Pipe_Data [] (ver más abajo).
NUSE_Pipe_Tail [] es una matriz U8 que tiene una entrada para cada canal configurado y apunta al final del canal del mensaje. Se utiliza como índice de dirección en NUSE_Pipe_Data [] (ver más abajo).
NUSE_Pipe_Items [] es una matriz de tipo U8 , que tiene una entrada para cada canal configurado y es un contador del número actual de mensajes en el canal. Estos datos son redundantes, ya que este valor se puede obtener a través de los índices de inicio y final del canal, pero la presencia de un contador simplifica el código.
NUSE_Pipe_Blocking_Count [] : esta matriz de tipo U8 contiene contadores del número de tareas bloqueadas en cada canal. Esta matriz solo se crea si el soporte de bloqueo de tareas está activado.

Todas estas estructuras de datos se inicializan con ceros mediante la función NUSE_Init_Pipe () cuando se inicia Nucleus SE. Esto es lógico, ya que todos los canales se crean vacíos (sin usar). Uno de los siguientes artículos contendrá una descripción completa de los procedimientos de inicio de Nucleus SE.

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

 RAM U8 NUSE_Pipe_Head[NUSE_PIPE_NUMBER]; RAM U8 NUSE_Pipe_Tail[NUSE_PIPE_NUMBER]; RAM U8 NUSE_Pipe_Items[NUSE_PIPE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Pipe_Blocking_Count[NUSE_PIPE_NUMBER]; #endif 

Datos de usuario RAM


Es responsabilidad del usuario proporcionar un área de datos en la RAM para almacenar los datos de cada canal configurado. El tamaño de esta área debe contener una matriz de tipo U8 , en la que caben todos los mensajes del canal.

Datos ROM


La estructura de estos datos es la siguiente:

NUSE_Pipe_Data [] es una matriz de tipo ADDR que tiene un registro para cada canal configurado e indica el área de datos de cada canal (consulte la sección "Datos de usuario en RAM" más arriba).
NUSE_Pipe_Size [] es una matriz de tipo U8 , que tiene una entrada para cada canal configurado y muestra la cantidad de mensajes que pueden caber en cada canal.
NUSE_Pipe_Message_Size [] es una matriz de tipo U8 que tiene un registro para cada canal configurado y muestra el tamaño de los mensajes (en bytes) que se pueden colocar en cada canal.

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

 ROM ADDR *NUSE_Pipe_Data[NUSE_PIPE_NUMBER] = { /* addresses of pipe data areas ------ */ }; ROM U8 NUSE_Pipe_Size[NUSE_PIPE_NUMBER] = { /* pipe sizes ------ */ }; ROM U8 NUSE_Pipe_Message_Size[NUSE_PIPE_NUMBER] = { /* pipe message sizes ------ */ }; 

Memoria de canal


Al igual que todos los demás objetos centrales de Nucleus SE, la cantidad de memoria necesaria para los canales es predecible.

La cantidad de datos en ROM (en bytes) para todos los canales en la aplicación se puede calcular de la siguiente manera:

NUSE_PIPE_NUMBER * (sizeof (ADDR) + 2)

La cantidad de datos del kernel en RAM (en bytes) para todos los canales de aplicación cuando se activan las tareas se puede calcular de la siguiente manera:

NUSE_PIPE_NUMBER * 4

De lo contrario:

NUSE_PIPE_NUMBER * 3

La cantidad de datos de usuario en RAM (en bytes) para el canal con el índice de canalización :

NUSE_Pipe_Size [tubería] * NUSE_Pipe_Message_Size [tubería]

Llamadas API no realizadas


Cuatro llamadas de servicio API Nucleus RTOS no se implementan en Nucleus SE.

Creación de canales


Esta llamada a la API crea un canal. Nucleus SE no necesita esto porque los canales se crean estáticamente.

Prototipo de llamada de servicio:

ESTADO NU_Create_Pipe (NU_PIPE * pipe, CHAR * name, VOID * start_address, UNSIGNED pipe_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);

Parámetros:

pipe : un puntero al bloque de control de canal proporcionado por el usuario; se usará como activador del canal principal en otras llamadas API;
nombre : puntero a un nombre de canal de 7 caracteres con un cero final;
start_address : dirección de inicio del canal;
pipe_size : el número total de bytes en el canal;
message_type : tipo de mensaje admitido por el canal. Puede tomar los valores NU_FIXED_SIZE o NU_VARIABLE_SIZE ;
message_size : si el canal admite mensajes de longitud fija, este parámetro indica el tamaño exacto de cada mensaje. De lo contrario, si el canal admite mensajes de longitud variable, este valor será el tamaño máximo del mensaje;
suspend_type : indica el tipo de suspensión de tareas en el canal. Puede tomar los valores NU_FIFO y NU_PRIORITY (planificador FIFO y planificador PRIORITY , respectivamente).

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_PIPE : puntero nulo a la unidad de control de canal ( NULL ), o la unidad de control ya está en uso;
NU_INVALID_MEMORY : se especificó un área de datos incorrecta en start_address ;
NU_INVALID_MESSAGE : parámetro de tipo de mensaje no válido;
NU_INVALID_SIZE : el tamaño del mensaje es mayor que el tamaño del canal o el tamaño del canal o del mensaje es cero;
NU_INVALID_SUSPEND : parámetro inválido suspend_type .

Eliminar canal


Esta llamada a la API elimina un canal creado previamente. Nucleus SE no lo necesita porque los canales se crean estáticamente y no se pueden eliminar.

Prototipo de llamada de servicio:
ESTADO NU_Delete_Pipe (tubería NU_PIPE *);

Parámetros:
pipe : un puntero a un bloque de control de canal.

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

Punteros de canal


Esta llamada a la API crea una lista secuencial de punteros a todos los canales del sistema. En Nucleus SE, no es necesario, ya que los canales se identifican mediante un índice simple, no un puntero, por lo tanto, dicha función sería redundante.

Prototipo de llamada de servicio:
NU_Pipe_Pointers SIN FIRMAR (NU_PIPE ** pointer_list, UNSIGNED maximum_pointers);

Parámetros:
pointer_list : puntero a una matriz de punteros NU_PIPE . Esta matriz se llenará con punteros a canales creados previamente en el sistema;
punteros máximos : el número máximo de punteros en la matriz.

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

Transmitir a un canal


Esta llamada a la API pasa el mensaje a todas las tareas que esperan mensajes de un canal específico. En Nucleus SE, esta característica no se ha implementado ya que agrega complejidad redundante.

Prototipo de llamada de servicio:
ESTADO NU_Broadcast_To_Pipe (tubería NU_PIPE *, mensaje VOID *, tamaño SIN FIRMAR, suspensión SIN FIRMAR);

Parámetros:
tubería : un puntero a un bloque de control de canal;
mensaje : puntero al mensaje transmitido;
tamaño : el número de elementos de datos NO FIRMADOS en el mensaje. Si el canal admite mensajes de longitud variable, este parámetro debe ser igual o menor que el tamaño del mensaje admitido por el canal. Si el canal admite mensajes de longitud fija, este parámetro debe ser exactamente del tamaño de los mensajes admitidos por el canal;
suspender : indica si se suspende la tarea de llamada si el canal ya está lleno. 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_PIPE : puntero no válido al canal;
NU_INVALID_POINTER : puntero nulo a un mensaje ( NULL );
NU_INVALID_SIZE : el tamaño del mensaje especificado es incompatible con el tamaño del mensaje especificado al crear el canal;
NU_INVALID_SUSPEND : intento de suspender un hilo no relacionado con la tarea;
NU_PIPE_FULL : no hay suficiente espacio en el canal para el mensaje;
NU_TIMEOUT : el canal aún está lleno, incluso después de que haya expirado el período de tiempo de espera especificado;
NU_PIPE_DELETED : el canal se eliminó mientras se suspendió la tarea;
NU_PIPE_RESET : el canal 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. Los canales 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 (bloque de control) que tiene un tipo de datos específico. Un puntero a esta unidad de control sirve como un identificador de canal. 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_PIPE como el equivalente de U8 , una variable (no un puntero) de este tipo sirve como identificador de canal. 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 canales. 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 un canal para procesar mensajes que consisten en un número arbitrario de bytes, al igual que Nucleus SE. Nucleus RTOS también admite canales de mensajes de longitud variable para los que solo se especifica el tamaño máximo del mensaje en el momento de la creación. Los mensajes de longitud variable no son compatibles con Nucleus SE.

Tamaño del canal


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

Llamadas API no realizadas


Nucleus RTOS admite diez gastos generales de canal. Cuatro de ellos no están implementados en Nucleus SE. Puede encontrar una descripción detallada de estas llamadas, así como los motivos de esta decisión, en la sección "Llamadas API no realizadas" anteriormente en este artículo.

En el siguiente artículo consideraremos la hora del sistema.

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/es433374/


All Articles