Toute la vérité sur RTOS. Article # 22. Boîtes aux lettres: services auxiliaires et structures de données



Cet article poursuit l'examen des boîtes aux lettres qui a commencé dans l'article précédent de la série «La vérité sur RTOS».

Articles précédents de la série:

Article # 21. Boîtes aux lettres: introduction et services de base
Article # 20. Sémaphores: services auxiliaires et structures de données
Article # 19. Sémaphores: introduction et services de base
Article # 18. Groupes d'indicateurs d'événements: services d'assistance et structures de données
Article # 17. Groupes de drapeaux d'événements: introduction et services de base
Article # 16. Signaux
Article # 15. Partitions de mémoire: services et structures de données
Article # 14. Sections de mémoire: introduction et services de base
Article # 13. Structures de données de tâche et appels d'API non pris en charge
Article # 12. Services pour travailler avec des tâches
Article # 11. Tâches: configuration et introduction à l'API
Article # 10. Scheduler: fonctionnalités avancées et préservation du contexte
Article # 9. Scheduler: implémentation
Article # 8. Nucleus SE: conception interne et déploiement
Article # 7. Nucleus SE: Introduction
Article # 6. Autres services RTOS
Article # 5. Interaction et synchronisation des tâches
Article # 4. Tâches, changement de contexte et interruptions
Article # 3. Tâches et planification
Article # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.


Services auxiliaires de boîtes aux lettres


Nucleus RTOS dispose de quatre appels d'API qui fournissent des fonctions auxiliaires liées aux boîtes aux lettres: vidage d'une boîte aux lettres, récupération d'informations sur une boîte aux lettres, récupération du nombre de boîtes aux lettres dans une application et récupération de pointeurs vers toutes les boîtes aux lettres d'une application. Les trois premières de ces fonctionnalités sont implémentées dans Nucleus SE.

Réinitialisation de la boîte aux lettres


Cet appel de service API réinitialise la boîte aux lettres à son état initial non utilisé. Le message stocké dans la boîte aux lettres sera perdu. Toutes les tâches suspendues sur la boîte aux lettres reprendront avec le code retour NUSE_MAILBOX_WAS_RESET .

Appel pour réinitialiser une boîte aux lettres dans Nucleus RTOS
Prototype d'appel de service:
STATUS NU_Reset_Mailbox (boîte aux lettres NU_MAILBOX *);

Paramètres:
boîte aux lettres - un pointeur vers l'unité de contrôle de boîte aux lettres.

Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_MAILBOX - pointeur de boîte aux lettres non valide.

Appel pour réinitialiser une boîte aux lettres dans Nucleus SE
Cet appel de service d'API prend en charge la fonctionnalité de base de l'API Nucleus RTOS.

Prototype d'appel de service:
STATUS NUSE_Mailbox_Reset (boîte aux lettres NUSE_MAILBOX);

Paramètres:
boîte aux lettres - index (ID) de la boîte aux lettres vidée.

Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_MAILBOX - index de boîte aux lettres non valide.

Implémenter la réinitialisation de la boîte aux lettres dans Nucleus SE
Le code d'option pour la fonction NUSE_Mailbox_Reset (après vérification des paramètres) est sélectionné à l'aide de la compilation conditionnelle, selon que la prise en charge des tâches de blocage (pause) est activée ou non. Nous considérerons ces deux options.

Si le verrou n'est pas activé, le code de cette fonction API est assez simple. La boîte aux lettres est marquée comme inutilisée en définissant le paramètre NUSE_Mailbox_Status [] sur FALSE .

Si le verrou est activé, le code devient plus complexe:

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

La boîte aux lettres est réinitialisée à l'état «Vide».

Chaque tâche suspendue dans la boîte aux lettres se voit attribuer le statut «Prêt» avec le code retour NUSE_MAILBOX_WAS_RESET . Une fois ce processus terminé, si le planificateur de priorité est utilisé, l'appel de service NUSE_Reschedule () est effectué , car une ou plusieurs tâches avec une priorité plus élevée peuvent devenir prêtes et attendre la permission de s'exécuter.

Récupération des informations de boîte aux lettres


Cet appel de service fournit un ensemble d'informations sur la boîte aux lettres. 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 et l'ordre de pause ne sont pas pris en charge et la pause de tâche peut être désactivée.

Appelez pour obtenir des informations sur la boîte aux lettres Nucleus RTOS
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:
STATUS NU_Mailbox_Information (boîte aux lettres NU_MAILBOX *, nom CHAR *, OPTION * suspend_type, DATA_ELEMENT * message_present, UNSIGNED * tasks_waiting, NU_TASK ** first_task);

Paramètres:

boîte aux lettres - pointeur vers l'unité de commande de boîte aux lettres;
nom - un pointeur de 8 caractères sur le nom de la boîte aux lettres. L'octet nul de fin est également inclus dans cette zone;
suspend_type - pointeur sur la variable dans laquelle le type de suspension de la tâche est stocké. Il peut prendre les valeurs NU_FIFO et NU_PRIORITY ;
message_present - un pointeur vers une variable qui prendra la valeur NU_TRUE ou NU_FALSE , selon que la boîte aux lettres est pleine ou non;
tasks_waiting - un pointeur sur une variable qui prendra le nombre de tâches suspendues sur cette boîte aux lettres;
first_task - un pointeur vers un pointeur de tâche qui prendra un pointeur vers la première tâche suspendue.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_MAILBOX - pointeur de boîte aux lettres non valide.

Appelez pour obtenir des informations sur la boîte aux lettres Nucleus SE
Cet appel de service d'API prend en charge la fonctionnalité de base de l'API Nucleus RTOS.

Prototype d'appel de service:

STATUS NUSE_Mailbox_Information (boîte aux lettres NUSE_MAILBOX, U8 * message_present, U8 * tasks_waiting, NUSE_TASK * first_task);

Paramètres:

boîte aux lettres - index de la boîte aux lettres pour laquelle des informations sont demandées;
message_present - un pointeur vers une variable qui prend la valeur TRUE ou FALSE , selon que la boîte aux lettres est pleine ou non;
tasks_waiting - un pointeur sur une variable qui prendra le nombre de tâches suspendues sur cette boîte aux lettres (rien n'est retourné si la suspension des tâches est désactivée);
first_task - un pointeur vers une variable de type NUSE_TASK , qui prendra l'index de la première tâche suspendue (rien n'est retourné si la suspension de la tâche est désactivée).

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_MAILBOX - index de boîte aux lettres non valide;
NUSE_INVALID_POINTER - un ou plusieurs paramètres de pointeur sont incorrects.

Implémentation des informations de boîte aux lettres dans Nucleus SE

L'implémentation de cet appel API est assez simple:

 *message_present = NUSE_Mailbox_Status[mailbox]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Mailbox_Blocking_Count[mailbox]; if (NUSE_Mailbox_Blocking_Count[mailbox] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_MAILBOX_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == mailbox)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif return NUSE_SUCCESS; 

La fonction renvoie l'état de la boîte aux lettres. Ensuite, si des appels de service pour bloquer des tâches sont activés, le nombre de tâches suspendues et l'index de la première sont renvoyés (sinon, ces paramètres sont définis sur 0).

Obtenir le nombre de boîtes aux lettres


Cet appel d'utilitaire renvoie le nombre de boîtes aux lettres dans l'application. Alors que dans Nucleus RTOS, leur nombre peut changer au fil du temps, et la valeur de retour montrera le nombre actuel de boîtes aux lettres, dans Nucleus SE, le nombre de boîtes aux lettres est défini au stade de la construction et ne peut pas être modifié.

Appel d'un compteur de boîtes aux lettres dans Nucleus RTOS
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:
UNSIGNED NU_Established_Mailboxes (VOID);

Paramètres:
Sont absents.

Valeur de retour:
Le nombre de boîtes aux lettres créées dans l'application.

Appel d'un compteur de boîtes aux lettres dans Nucleus SE
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:
U8 NUSE_Mailbox_Count (void);

Paramètres:
Sont absents.

Valeur de retour:
Nombre de boîtes aux lettres configurées dans l'application.

Implémentation d'un compteur de boîtes aux lettres dans Nucleus SE
L'implémentation de cet appel API est extrêmement simple: la valeur de la directive #define NUSE_MAILBOX_NUMBER est retournée .

Structures de données


Les boîtes aux lettres utilisent deux ou trois tableaux de structures de données (toutes situées dans la RAM), qui, comme les autres objets Nucleus SE, sont un ensemble de tables dont la taille dépend du nombre de boîtes aux lettres configurées et de leurs paramètres.

Je recommande fortement que le code d'application n'utilise pas un accès direct à ces structures de données, mais s'y réfère via les fonctions API fournies. Cela évite l'incompatibilité avec les futures versions de Nucleus SE et les effets secondaires indésirables, et simplifie également le portage de l'application vers Nucleus RTOS. Ce qui suit est un aperçu détaillé des structures de données pour une meilleure compréhension du fonctionnement du code d'appel de service et pour le débogage.

Données RAM


Ces données ont la structure suivante:

NUSE_Mailbox_Data [] - un tableau de type ADDR , qui a une entrée pour chaque boîte aux lettres configurée, il stocke les données de boîte aux lettres.
NUSE_Mailbox_Status [] est un tableau U8 qui a une entrée pour chaque boîte aux lettres configurée, il surveille l'utilisation des boîtes aux lettres. Une valeur non nulle ( TRUE ) indique que la boîte aux lettres est pleine.
NUSE_Mailbox_Blocking_Count [] - un tableau de type U8 , il contient un compteur de tâches bloquées pour chaque boîte aux lettres. Ce tableau est créé uniquement si la fonctionnalité de blocage d'appels API est activée.

Ces structures de données sont initialisées avec des zéros dans la fonction NUSE_Init_Mailbox () au démarrage de Nucleus SE. C'est logique, car chaque boîte aux lettres est créée vide (inutilisée).

Voici les définitions de ces structures de données du fichier nuse_init.c .

 RAM ADDR NUSE_Mailbox_Data[NUSE_MAILBOX_NUMBER]; RAM U8 NUSE_Mailbox_Status[NUSE_MAILBOX_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Mailbox_Blocking_Count[NUSE_MAILBOX_NUMBER]; #endif 

Données ROM


Pour l'implémentation des boîtes aux lettres, les données en ROM ne sont pas utilisées.

La quantité de mémoire pour les boîtes aux lettres


Comme pour tous les objets du noyau Nucleus SE, la quantité de mémoire requise pour les boîtes aux lettres est connue à l'avance.

La quantité de mémoire pour les données dans la ROM pour toutes les boîtes aux lettres de l'application est de 0.

La quantité de données dans la RAM pour toutes les boîtes aux lettres de l'application (en octets) avec des appels d'API activés pour bloquer les tâches peut être calculée comme suit:
NUSE_MAILBOX_NUMBER * (taille de (ADDR) +2)

Sinon:
NUSE_MAILBOX_NUMBER * (taille de (ADDR) +1)

Appels d'API non réalisés


Les quatre appels d'utilitaires disponibles dans Nucleus RTOS ne sont pas implémentés dans Nucleus SE.

Créer une boîte aux lettres


Cet appel de service API crée une boîte aux lettres. Nucleus SE n'en a pas besoin, car les boîtes aux lettres sont créées statiquement.

Prototype d'appel de service:
STATUS NU_Create_Mailbox (boîte aux lettres NU_MAILBOX *, nom CHAR *, UNSIGNED OPTION suspend_type);

Paramètres:

boîte aux lettres - un pointeur vers l'unité de commande de boîte aux lettres fourni par l'utilisateur; Utilisé pour gérer les boîtes aux lettres dans d'autres appels d'API
nom - pointeur vers le nom à 7 caractères de la boîte aux lettres avec zéro octet de fin;
suspend_type - Indique le principe de la suspension d'une tâche sur une boîte aux lettres. 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_MAILBOX - pointeur nul vers l'unité de contrôle de boîte aux lettres ( NULL ), ou le pointeur est déjà utilisé;
NU_INVALID_SUSPEND - paramètre suspend_type non valide .

Supprimer une boîte aux lettres


Cet appel de service API supprime une boîte aux lettres créée précédemment. Nucleus SE n'en a pas besoin, car les boîtes aux lettres sont créées statiquement et ne peuvent pas être supprimées.

Prototype d'appel de service:

STATUS NU_Delete_Mailbox (boîte aux lettres NU_MAILBOX *);

Paramètres:

boîte aux lettres - un pointeur vers l'unité de contrôle de boîte aux lettres.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_MAILBOX - pointeur de boîte aux lettres non valide.

Pointeurs de boîte aux lettres


Cet appel d'API constitue une liste séquentielle de pointeurs vers toutes les boîtes aux lettres du système. Nucleus SE n'en a pas besoin, car les boîtes aux lettres sont identifiées par un simple index, et non par un pointeur.

Prototype d'appel de service:

UNSIGNED NU_Mailbox_Pointers (NU_MAILBOX ** pointer_list, UNSIGNED maximum_pointers);

Paramètres:

pointer_list - pointeur vers un tableau de pointeurs NU_MAILBOX ; ce tableau sera rempli de pointeurs vers des boîtes aux lettres créées dans le système;
maximum_pointers - le nombre maximum de pointeurs dans le tableau.

Valeur de retour:

Nombre de pointeurs NU_MAILBOX dans le tableau.

Enregistrer un message dans la boîte aux lettres pour distribution à tous les destinataires


Cet appel de service envoie un message à toutes les tâches qui attendent des messages d'une boîte aux lettres spécifique. Dans Nucleus SE, cet appel d'utilitaire n'est pas implémenté, car il ajouterait une complexité inutile.

Prototype d'appel de service:

STATUS NU_Broadcast_To_Mailbox (boîte aux lettres NU_MAILBOX *, message VOID *, suspension UNSIGNED);

Paramètres:

boîte aux lettres - pointeur vers l'unité de commande de boîte aux lettres;
message - pointeur vers le message transmis;
suspend - indique s'il faut suspendre la tâche d'appel si la boîte aux lettres contient déjà un message; peut être NU_NO_SUSPEND , NU_SUSPEND ou une valeur de délai d'expiration.

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_MAILBOX - pointeur de boîte aux lettres non valide;
NU_INVALID_POINTER - pointeur nul vers un message ( NULL );
NU_INVALID_SUSPEND - tentative de suspension à partir d'un thread non lié à une tâche;
NU_MAILBOX_FULL - la boîte aux lettres contient déjà un message;
NU_TIMEOUT - une fois le délai expiré, la boîte aux lettres est toujours pleine;
NU_MAILBOX_DELETED - La boîte aux lettres a été supprimée lors de la suspension de la tâche.
NU_MAILBOX_RESET - la boîte aux lettres a été réinitialisée alors que la tâche a été suspendue.

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 boîtes aux lettres 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é qu'en conséquence, le code deviendra plus compréhensible et plus efficace en termes de quantité de mémoire requise. Sinon, les appels d'API Nucleus RTOS peuvent être directement portés vers Nucleus SE.

Identificateurs d'objet


Dans Nucleus RTOS, tous les objets sont décrits par des structures de données (unités de contrôle) d'un type spécifique. Un pointeur vers cette unité de contrôle sert d’identifiant à la boîte aux lettres. 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_MAILBOX comme l'équivalent de U8 , une variable (pas un pointeur) de ce type sert d'identifiant de la boîte aux lettres. 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 boîtes aux lettres. 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, un message de boîte aux lettres se compose de quatre mots de 32 bits. Dans Nucleus SE, j'ai décidé de réduire cette valeur à une variable de type ADDR . Cette modification entraîne des économies de mémoire importantes et un temps d'exécution des tâches réduit. Il suggère également que l'utilisation habituelle d'une boîte aux lettres consiste à transmettre des informations d'une tâche à une autre. Cette incompatibilité ne causera pas de gros problèmes lors du portage d'applications vers Nucleus RTOS. Nucleus SE peut être modifié si un format de message différent est nécessaire.

Appels d'API non réalisés


Nucleus RTOS prend en charge neuf appels de bureau de boîte aux lettres. Parmi ceux-ci, quatre ne sont pas implémentés dans Nucleus SE. Les détails de ces défis, ainsi que les raisons pour lesquelles ils ont été exclus de Nucleus SE, sont décrits ci-dessus.

Le prochain article examinera les files d'attente.

À 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.

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


All Articles