
Dans cet article, nous continuerons à considérer les files d'attente.
Services de file d'attente secondaire
Nucleus RTOS dispose de quatre appels d'API qui fournissent des fonctions auxiliaires liées aux files d'attente: réinitialisation d'une file d'attente, obtention d'informations sur les files d'attente, obtention du nombre de files d'attente dans une application et obtention de pointeurs vers toutes les files d'attente d'une application. Les trois premières fonctions sont implémentées dans Nucleus SE.
Articles précédents de la série:
Article # 23. Files d'attente: introduction et services de baseArticle # 22. Boîtes aux lettres: services auxiliaires et structures de donnéesArticle # 21. Boîtes aux lettres: introduction et services de baseArticle # 20. Sémaphores: services auxiliaires et structures de donnéesArticle # 19. Sémaphores: introduction et services de baseArticle # 18. Groupes d'indicateurs d'événements: services d'assistance et structures de donnéesArticle # 17. Groupes de drapeaux d'événements: introduction et services de baseArticle # 16. SignauxArticle # 15. Partitions de mémoire: services et structures de donnéesArticle # 14. Sections de mémoire: introduction et services de baseArticle # 13. Structures de données de tâche et appels d'API non pris en chargeArticle # 12. Services pour travailler avec des tâchesArticle # 11. Tâches: configuration et introduction à l'APIArticle # 10. Scheduler: fonctionnalités avancées et préservation du contexteArticle # 9. Scheduler: implémentationArticle # 8. Nucleus SE: conception interne et déploiementArticle # 7. Nucleus SE: IntroductionArticle # 6. Autres services RTOSArticle # 5. Interaction et synchronisation des tâchesArticle # 4. Tâches, changement de contexte et interruptionsArticle # 3. Tâches et planificationArticle # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.Réinitialisation de la file d'attente
Cet appel d'API réinitialise la file d'attente à son état d'origine non utilisé. Tous les messages stockés dans la file d'attente seront perdus. Toutes les tâches suspendues dans la file d'attente reprendront avec le code retour
NUSE_QUEUE_WAS_RESET .
Appel de réinitialisation de file d'attente dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Reset_Queue (file d'attente NU_QUEUE *);Paramètres:
queue - un pointeur vers un bloc de contrôle de file d'attente fourni par l'utilisateur.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.
Appel de réinitialisation de file d'attente dans Nucleus SECet appel d'utilitaire prend en charge la fonctionnalité principale de l'API RTOS Nucleus.
Prototype d'appel de service:
STATUS NUSE_Queue_Reset (file d'attente NUSE_QUEUE);Paramètres:
queue - index (ID) de la file d'attente vidée.
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_QUEUE - index de file d'attente non valide.
Implémentation de la réinitialisation de file d'attente dans Nucleus SELe code de la fonction
NUSE_Queue_Reset (après vérification des paramètres) est assez simple. Les index de la tête et de la queue de la file d'attente, ainsi que le compteur de messages dans la file d'attente, se voient attribuer une valeur nulle.
Si le verrouillage des tâches est activé, un code supplémentaire est responsable de la restauration des tâches suspendues:
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
Chaque tâche en pause dans la file d'attente se voit attribuer un état «prêt» avec un code retour
NUSE_QUEUE_WAS_RESET . Une fois ce processus terminé, si le planificateur de priorité est utilisé, la fonction
NUSE_Reschedule () est
appelée , car une ou plusieurs tâches avec une priorité élevée peuvent être prêtes à être exécutées.
Obtention d'informations sur la file d'attente
Cet appel de service fournit des informations sur la file d'attente. L'implémentation de cet appel dans Nucleus SE diffère de Nucleus RTOS en ce qu'il renvoie moins d'informations, car la dénomination des objets, la longueur variable des messages et l'ordre de pause des tâches ne sont pas pris en charge et le verrouillage des tâches peut être désactivé.
Appel à des informations de file d'attente dans Nucleus RTOSPrototype d'appel de service:
STATUT NU_Queue_Information (NU_QUEUE * file d'
attente, CHAR * nom, start_address ** NUL, UNSIGNED * queue_size, UNSIGNED * disponible, UNSIGNED * messages, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * tasks_waiting, NU_TASK ** first_task);
Paramètres:
file d'attente - un pointeur vers un bloc de contrôle de file d'attente fourni par l'utilisateur;
nom - pointeur vers la région à 8 caractères pour le nom du message dans la file d'attente;
start_address - un pointeur vers un pointeur dans lequel l'adresse du début de la zone de données de file d'attente sera écrite;
queue_size - un pointeur vers une variable pour stocker le nombre total d'éléments
UNSIGNED dans la file d'attente;
available - un pointeur sur une variable pour stocker le nombre d'éléments
UNSIGNED disponibles dans la file d'attente;
messages - un pointeur sur une variable pour stocker le nombre actuel de messages dans la file d'attente;
message_type - un pointeur vers une variable pour stocker le type de messages pris en charge par la file d'attente. Les valeurs valides sont
NU_FIXED_SIZE et
NU_VARIABLE ;
message_size - un pointeur vers une variable pour stocker le nombre d'éléments de données
UNSIGNED dans chaque message de la file d'attente. Si la file d'attente prend en charge les messages de longueur variable, ce nombre indique la longueur maximale des messages;
suspend_type - un pointeur vers une variable pour stocker le type de suspension des tâches. Les valeurs valides sont
NU_FIFO et
NU_PRIORITY ;
tasks_waiting - un pointeur sur une variable pour stocker le nombre de tâches suspendues dans cette file d'attente;
first_task - pointeur vers le pointeur de tâche, dans lequel le pointeur de la première tâche suspendue est placé.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.
Appel d'informations sur la file d'attente dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
STATUS NUSE_Queue_Information (file d'attente NUSE_QUEUE, ADDR * start_address, U8 * queue_size, U8 * available, U8 * messages, U8 * tasks_waiting, NUSE_TASK * first_task);Paramètres:
file d'attente - index de la file d'attente pour laquelle des informations sont demandées;
start_address - pointeur vers une variable de type
ADDR , qui stockera l'adresse du début de la zone de données de la file d'attente;
queue_size - un pointeur vers une variable de type
U8 , qui stockera le nombre total de messages pouvant tenir dans la file d'attente;
disponible - un pointeur sur une variable de type
U8 , qui stockera le nombre de places libres dans la file d'attente;
messages - un pointeur sur une variable de type
U8 , qui stockera le nombre actuel de messages dans la file d'attente;
tasks_waiting - un pointeur vers une variable dans laquelle le nombre de tâches suspendues dans cette file d'attente sera stocké (rien n'est retourné si le verrouillage des tâches est désactivé);
first_task - un pointeur vers une variable de type
NUSE_TASK dans laquelle l'index de la première tâche suspendue sera stocké (rien n'est retourné si le verrouillage de tâche est désactivé).
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_QUEUE - index de file d'attente non valide;
NUSE_INVALID_POINTER - un ou plusieurs paramètres de pointeur sont incorrects.
Implémentation de l'affichage des informations de file d'attente dans Nucleus SEL'implémentation de cet appel d'API est assez 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 fonction renvoie l'état de la file d'attente. Ensuite, si le verrouillage des tâches est activé, le nombre de tâches en attente et l'index de la première d'entre elles sont renvoyés (sinon, les deux paramètres sont définis sur 0).
Obtenir le nombre de files d'attente
Cet appel d'utilitaire renvoie le nombre de files d'attente configurées dans l'application. Dans Nucleus RTOS, leur nombre peut changer au fil du temps et la valeur de retour indiquera le nombre actuel de files d'attente. Dans Nucleus SE, la valeur de retour est définie pendant la phase de génération et ne peut pas être modifiée.
Appel du compteur de files d'attente dans Nucleus RTOSPrototype d'appel de service:
UNSIGNED NU_Established_Queues (VOID);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de files d'attente créées dans le système.
Appel du compteur de file d'attente dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
U8 NUSE_Queue_Count (void);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de files d'attente configurées dans l'application.
Implémentation du compteur de files d'attente dans Nucleus SEL'implémentation de cet appel API est très simple: la valeur du symbole
#define NUSE_QUEUE_NUMBER est
retournée .
Structures de données
Les files d'attente utilisent cinq ou six structures de données (qui sont soit en RAM ou en ROM), qui sont des ensembles de tables (comme les autres objets Nucleus SE), dont le nombre et la taille correspondent au nombre de files d'attente dans l'application et aux paramètres sélectionnés.
Données du noyau dans la RAM
Ces données ont la structure suivante:
NUSE_Queue_Head [] est un tableau de pointeurs de type
U8 , possède une entrée pour chaque file d'attente configurée et pointe vers la tête de la file d'attente de messages. Utilisé comme index d'adresse dans
NUSE_Queue_Data [] (voir ci-dessous);
NUSE_Queue_Tail [] est un tableau de type
U8 , possède une entrée pour chaque file d'attente configurée dans l'application et pointe vers la fin de la file d'attente de messages. Utilisé comme index d'adresse dans
NUSE_Queue_Data [] (voir ci-dessous);
NUSE_Queue_Items [] est un tableau de type
U8 , a une entrée pour chaque file d'attente configurée et est un compteur de messages dans la file d'attente. Ces données peuvent être considérées comme redondantes, car ces valeurs peuvent être obtenues via les index du début et de la fin de la file d'attente, cependant, le stockage du compteur simplifie le code;
NUSE_Queue_Blocking_Count [] - ce tableau de type
U8 contient des compteurs du nombre de tâches suspendues sur chaque file d'attente. Ce tableau est créé uniquement si la prise en charge du verrouillage des tâches est activée.
Ces structures de données sont initialisées en zéros par la fonction
NUSE_Init_Queue () au démarrage de Nucleus SE. C'est logique, car toutes les files d'attente sont créées vides (non utilisées).
Voici les définitions de ces structures dans le fichier
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
Données utilisateur RAM
L'utilisateur est responsable de fournir une zone RAM pour stocker chaque file d'attente. La taille de cette zone doit contenir un tableau de type
ADDR , dans lequel chaque enregistrement correspond à un message dans la file d'attente
Données ROM
Ces données ont la structure suivante:
NUSE_Queue_Data [] - un tableau de type
ADDR , a une entrée pour chaque file d'attente configurée et pointe vers la zone de données de la file d'attente (voir. Données RAM utilisateur);
NUSE_Queue_Size [] - un tableau de type
U8 , a une entrée pour chaque file d'attente configurée et affiche le nombre maximal de messages que chaque file d'attente peut recevoir.
Ces structures de données sont déclarées et initialisées (statiquement) dans le fichier
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 quantité de mémoire pour les files d'attente
Comme tous les objets du noyau Nucleus SE, la quantité de mémoire nécessaire pour les files d'attente est facilement prévisible.
La quantité de données dans la ROM (en octets) pour toutes les files d'attente dans l'application peut être calculée comme suit:
NUSE_QUEUE_NUMBER * (taille de (ADDR) + 1)La quantité de données du noyau dans la RAM (en octets) pour toutes les files d'attente dans l'application avec le verrouillage de tâche activé est calculée comme suit:
NUSE_QUEUE_NUMBER * 3Si le verrouillage est désactivé:
NUSE_QUEUE_NUMBER * 4La quantité de données utilisateur en RAM (en octets) pour la file d'attente avec l'index de
file d'attente :
NUSE_Queue_Size [queue] * sizeof (ADDR)Appels d'API non réalisés
Quatre appels d'API qui peuvent être trouvés dans Nucleus RTOS ne sont pas implémentés dans Nucleus SE:
Création de file d'attente
Cet appel API crée une file d'attente; dans Nucleus SE, cela n'est pas nécessaire, car les files d'attente sont créées statiquement.
Prototype d'appel de service:
STATUS NU_Create_Queue (file d'attente NU_QUEUE *, nom char *, VOID * start_address, UNSIGNED queue_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);Paramètres:
file d'attente - un pointeur vers une unité de contrôle fournie par l'utilisateur; il est utilisé pour gérer les files d'attente dans d'autres appels d'API;
nom - un pointeur vers un nom de file d'attente à 7 caractères avec un octet de fin nul;
start_address - adresse du début de la file d'attente;
message_type - type de message pris en charge par la file d'attente. Il peut prendre les valeurs
NU_FIXED_SIZE ou
NU_VARIABLE_SIZE ;
message_size - si la file d'attente prend en charge les messages d'une longueur fixe, ce paramètre définit la longueur exacte de chaque message, sinon, si la file d'attente prend en charge les messages de longueur variable, cette valeur est la longueur maximale du message;
suspend_type - détermine le type de suspension des tâches dans la file d'attente. Il peut prendre les valeurs
NU_FIFO et
NU_PRIORITY , qui désignent respectivement le principe de FIFO (First-In-First-Out) ou le principe de priorité de suspension des tâches.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur nul vers le bloc de contrôle de file d'attente (
NULL ), ou le pointeur est déjà utilisé;
NU_INVALID_MEMORY - zone de mémoire non valide spécifiée dans
start_address ;
NU_INVALID_MESSAGE - paramètre de type de
message non valide;
NU_INVALID_SIZE - la file d'attente ne prend pas en charge les messages de cette longueur, ou la taille de la file d'attente et / ou la longueur des messages est 0;
NU_INVALID_SUSPEND - paramètre
suspend_type non
valide .
Supprimer la file d'attente
Cet appel d'API supprime la file d'attente créée précédemment. Nucleus SE n'en a pas besoin car les files d'attente sont créées statiquement et ne peuvent pas être supprimées.
Prototype d'appel de service:
STATUS NU_Delete_Queue (file d'attente NU_QUEUE *);Paramètres:
queue - un pointeur vers un bloc de contrôle de file d'attente.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide.
Pointeurs de file d'attente
Cet appel d'API crée une liste séquentielle de pointeurs vers toutes les files d'attente du système. Nucleus SE n'en a pas besoin car les files d'attente sont identifiées à l'aide d'un simple index, et non d'un pointeur.
Prototype d'appel de service:
UNSIGNED NU_Queue_Pointers (NU_QUEUE ** pointer_list, UNSIGNED maximum_pointers);Paramètres:
pointer_list - pointeur vers un tableau de pointeurs
NU_QUEUE . Ce tableau sera rempli de pointeurs vers les files d'attente créées dans le système;
maximum_pointers - le nombre maximum de pointeurs dans le tableau.
Valeur de retour:
Le nombre de pointeurs
NU_QUEUE dans le tableau.
Mise en file d'attente (diffusion vers la file d'attente)
Cet appel d'API transmet le message à toutes les tâches suspendues dans la file d'attente qui attendent des messages de la file d'attente spécifiée. Cette fonctionnalité n'est pas implémentée dans Nucleus SE car elle ajoute de la redondance.
Prototype d'appel de service:
STATUS NU_Broadcast_To_Queue (file d'attente NU_QUEUE *, message VOID *, taille UNSIGNED, suspension UNSIGNED);Paramètres:
queue - un pointeur vers un bloc de contrôle de file d'attente;
message - pointeur vers le message transmis;
size - le nombre d'éléments
UNSIGNED dans le message. Si la file d'attente prend en charge les messages de longueur variable, ce paramètre doit être égal ou inférieur à la longueur de message prise en charge par la file d'attente. Si la file d'attente prend en charge les messages d'une longueur fixe, ce paramètre doit être égal à la longueur du message pris en charge par la file d'attente;
suspen - indique s'il faut suspendre la tâche appelante si la file d'attente est déjà pleine. Il peut s'agir de
NU_NO_SUSPEND ,
NU_SUSPEND ou d'une valeur de délai d'expiration.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_QUEUE - pointeur de file d'attente non valide;
NU_INVALID_POINTER - pointeur nul vers un message (
NULL );
NU_INVALID_SIZE - la longueur de message spécifiée n'est pas compatible avec la longueur spécifiée lors de la création de la file d'attente;
NU_INVALID_SUSPEND - tente de suspendre une tâche à partir d'un thread non associé à la tâche;
NU_QUEUE_FULL - il n'y a pas assez d'espace dans la file d'attente pour le message;
NU_TIMEOUT - la file d'attente est toujours pleine après l'expiration du délai;
NU_QUEUE_DELETED - la file d'attente a été supprimée alors que la tâche a été suspendue;
NU_QUEUE_RESET - La file d'attente a été réinitialisée lors de la suspension de la tâche.
Compatible avec Nucleus RTOS
Comme pour tous les autres objets Nucleus SE, mon objectif était de maximiser la compatibilité du code d'application avec Nucleus RTOS. Les files d'attente ne font pas exception et, du point de vue de l'utilisateur, elles sont implémentées de la même manière que dans Nucleus RTOS. Il y a aussi une certaine incompatibilité, que j'ai jugée acceptable, étant donné que le code deviendra ainsi plus compréhensible et plus efficace en termes de quantité de mémoire requise. Sinon, les appels d'API Nucleus RTOS peuvent être portés presque directement vers Nucleus SE.
Identificateurs d'objet
Dans Nucleus RTOS, tous les objets sont décrits par une structure de données (unités de contrôle) qui a un type de données spécifique. Un pointeur vers cette unité de contrôle sert d'identifiant pour la file d'attente. J'ai décidé que dans Nucleus SE, une approche différente est nécessaire pour une utilisation efficace de la mémoire: tous les objets du noyau sont décrits par un ensemble de tables en RAM et / ou ROM. La taille de ces tables est déterminée par le nombre d'objets configurés de chaque type. L'identifiant d'un objet particulier est l'index dans ce tableau. J'ai donc défini
NUSE_QUEUE comme l'équivalent de
U8 , une variable (pas un pointeur) de ce type sert d'identifiant de file d'attente. Cette légère incompatibilité est facile à gérer si le code est porté de Nucleus SE vers Nucleus RTOS et vice versa. En règle générale, aucune opération n'est effectuée sur les identificateurs d'objet autres que le déplacement et le stockage.
Nucleus RTOS prend également en charge la dénomination des files d'attente. Ces noms sont utilisés uniquement pour le débogage. Je les ai exclus de Nucleus SE pour économiser de la mémoire.
Taille et type du message
Dans Nucleus RTOS, une file d'attente peut être configurée pour traiter les messages composés d'un nombre
illimité d' éléments
non signés . Dans Nucleus SE, les files d'attente sont simplifiées et ne prennent en charge que les messages de type
ADDR uniques. Les canaux de données de Nucleus SE sont un peu plus flexibles et peuvent être une alternative utile aux files d'attente dans certains cas. Les chaînes seront couvertes dans les deux prochains articles de cette série.
Nucleus SE prend également en charge les files d'attente de messages de longueur variable, qui spécifient uniquement la longueur maximale des messages lors de la création. Les longueurs de message variables ne sont pas prises en charge par Nucleus SE
Taille de la file d'attente
Dans Nucleus SE, le nombre maximal de messages dans une file d'attente est de 256, car toutes les variables et constantes sont de type
U8 . Nucleus RTOS n'a pas de telles limitations.
Appels d'API non réalisés
Nucleus RTOS prend en charge dix appels de gestion de file d'attente. Parmi ceux-ci, quatre ne sont pas implémentés dans Nucleus SE. Les détails de ces appels, ainsi que les raisons d'une telle décision, peuvent être trouvés dans cet article ci-dessus, dans la section "Appels d'API non réalisés".
Le prochain article traitera des canaux de transmission de données.
À propos de l'auteur: Colin Walls travaille dans l'industrie électronique depuis plus de trente ans, consacrant la majeure partie de son temps au micrologiciel. Il est maintenant ingénieur firmware chez Mentor Embedded (une division de Mentor Graphics). Colin Walls intervient souvent lors de conférences et séminaires, auteur de nombreux articles techniques et de deux livres sur le firmware. Vit au Royaume-Uni.
Blog professionnel
de Colin , e-mail: colin_walls@mentor.com.