
Dans cet article, nous continuerons à considérer les canaux de transmission de données.
Services de support de canal
Nucleus RTOS dispose de quatre appels d'API qui fournissent des fonctions auxiliaires liées aux canaux: réinitialisation d'un canal, récupération des informations de canal, récupération du nombre de canaux dans une application et récupération de pointeurs vers tous les canaux d'une application. Les trois premières fonctions sont implémentées dans Nucleus SE.
Articles précédents de la série:
Article # 25. Canaux de données: introduction et services de baseArticle # 24. Files d'attente: services auxiliaires et structures de donnéesArticle # 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 des canaux
Cet appel d'API réinitialise le canal à son état d'origine non utilisé. Tous les messages qui y sont stockés seront perdus. Toutes les tâches suspendues sur le canal reprennent avec le code retour
NUSE_PIPE_WAS_RESET .
Appel de réinitialisation de canal dans Nucleus RTOSPrototype d'appel de service:
STATUS NU_Reset_Pipe (NU_PIPE * pipe);Paramètres:
pipe - un pointeur vers un bloc de contrôle de canal défini par l'utilisateur.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_PIPE - pointeur de canal invalide.
Défi de réinitialisation de canal dans Nucleus SECet appel de service d'API prend en charge la fonctionnalité de base de l'API Nucleus RTOS.
Prototype d'appel de service:
STATUS NUSE_Pipe_Reset (canal NUSE_PIPE);Paramètres:
pipe est l'index (ID) du
tuyau en cours de suppression.
Valeur de retour:
NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_PIPE - index de canal invalide.
Implémentation de réinitialisation de canal dans Nucleus SELe code de la fonction
NUSE_Pipe_Reset () (après vérification des paramètres) est assez simple. Les indices de début et de fin du canal, ainsi que le compteur de messages dans le canal, sont définis sur 0.
Si le verrouillage des tâches est activé, un code supplémentaire est responsable de la restauration des tâches suspendues:
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
Chaque tâche suspendue sur le canal se voit attribuer le statut «prêt» avec le code retour
NUSE_PIPE_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.
Infos sur la chaîne
Cet appel de service renvoie des informations sur le canal. L'implémentation de cet appel dans Nucleus SE diffère de Nucleus RTOS en ce qu'il renvoie moins d'informations. En effet, la dénomination des objets, les messages de longueur variable et l'ordre de pause des tâches ne sont pas pris en charge dans Nucleus SE et la pause des tâches peut être désactivée.
Appel pour des informations sur les canaux dans Nucleus RTOSPrototype d'appel de service:
STATUS 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 * tasks_waask **; firstParamètres:
pipe - pointeur vers le bloc de contrĂ´le de canal fourni par l'utilisateur;
nom - pointeur vers la zone de 8 caractères pour le nom du message du canal;
start_address - un pointeur vers un pointeur dans lequel l'adresse du début de la zone de données de canal sera écrite;
pipe_size - un pointeur vers une variable pour stocker le nombre total d'octets dans le canal;
available - pointeur sur une variable pour stocker le nombre d'octets disponibles dans le canal;
messages - un pointeur sur une variable pour stocker le nombre de messages dans le canal;
message_type - un pointeur vers une variable pour stocker le type de message pris en charge par le canal. Il peut prendre les valeurs
NU_FIXED_SIZE et
NU_VARIABLE_SIZE ;
message_size - pointeur vers une variable pour stocker le nombre d'octets dans chaque message de canal. Si le canal prend en charge les messages de longueur variable, ce nombre sera la taille maximale du message;
suspend_type - un pointeur vers une variable pour stocker le type de tâche de suspension. Il peut prendre les valeurs
NU_FIFO et
NU_PRIORITY ;
tasks_waiting - un pointeur sur une variable pour stocker le nombre de tâches suspendues sur ce canal;
first_task - un pointeur vers un pointeur vers la première tâche suspendue.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_PIPE - pointeur de canal invalide.
Appelez pour obtenir des informations sur les chaînes dans Nucleus SECet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.
Prototype d'appel de service:
STATUS NUSE_Pipe_Information (NUSE_PIPE pipe, ADDR * start_address, U8 * pipe_size, U8 * available, U8 * messages, U8 * message_size, U8 * tasks_waiting, NUSE_TASK * first_task);Paramètres:
pipe - index du canal, dont les informations sont demandées;
start_address - pointeur vers une variable de type
ADDR pour stocker l'adresse du début de la zone de données de canal;
pipe_size - un pointeur vers une variable de type
U8 pour stocker le nombre total de messages que le canal peut recevoir;
disponible - un pointeur sur une variable de type
U8 pour stocker le nombre de messages pour lesquels de l'espace libre est laissé dans le canal;
messages - un pointeur vers une variable de type
U8 pour stocker le nombre actuel de messages dans le canal;
message_size - pointeur vers une variable de type
U8 pour stocker la taille des messages traités par ce canal;
tasks_waiting - un pointeur sur une variable pour stocker le nombre de tâches suspendues sur ce canal (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_PIPE - index de canal invalide;
NUSE_INVALID_POINTER - un ou plusieurs paramètres de pointeur sont incorrects.
Implémentation des informations de canal dans Nucleus SEL'implémentation de cet appel d'API est assez 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 fonction renvoie l'état du canal. Ensuite, si les verrous de tâche sont activés, le nombre de tâches en attente et l'index de la première d'entre elles sont renvoyés (sinon, ces deux paramètres sont définis sur 0).
Obtenir le nombre de canaux
Cet appel de service renvoie le nombre de canaux configurés dans l'application. Dans Nucleus RTOS, cette valeur peut changer avec le temps et la valeur de retour indiquera le nombre actuel de canaux. 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 Ă un compteur de canaux dans Nucleus RTOSPrototype d'appel de service:
UNSIGNED NU_Established_Pipes (VOID);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de canaux créés dans le système.
Appel à un compteur de canaux dans Nucleus SECet appel d'utilitaire prend en charge les fonctionnalités de base de l'API RTOS Nucleus
Prototype d'appel de service:
U8 NUSE_Pipe_Count (void);Paramètres:
Sont absents.
Valeur de retour:
Le nombre de canaux configurés dans l'application.
Implémentation d'un compteur de canaux dans Nucleus SEL'implémentation de cet appel API est assez simple: la valeur du symbole
#define NUSE_PIPE_NUMBER est
retournée .
Structures de données
Les canaux utilisent six ou sept structures de données (qui sont soit en RAM ou en ROM), qui sont (comme les autres objets Nucleus SE) un ensemble de tables, dont la taille et le nombre correspondent au nombre de canaux configurés et à 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 évitera l'incompatibilité avec les futures versions de Nucleus SE et les effets secondaires indésirables, ainsi que simplifiera le portage des applications vers Nucleus RTOS. Voici un aperçu détaillé des structures de données pour simplifier la compréhension des appels de service et du code de débogage.
Données du noyau dans la RAM
Ces données ont la structure suivante:
NUSE_Pipe_Head [] est un tableau de pointeurs de type
U8 , ayant une entrée pour chaque canal configuré et indiquant le début du canal de message. Utilisé comme index d'adresse dans
NUSE_Pipe_Data [] (voir ci-dessous).
NUSE_Pipe_Tail [] est un tableau
U8 qui a une entrée pour chaque canal configuré et pointe vers la fin du canal de message. Utilisé comme index d'adresse dans
NUSE_Pipe_Data [] (voir ci-dessous).
NUSE_Pipe_Items [] est un tableau de type
U8 , qui a une entrée pour chaque canal configuré et est un compteur du nombre actuel de messages dans le canal. Ces données sont redondantes, car cette valeur peut être obtenue via les indices de début et de fin de canal, mais la présence d'un compteur simplifie le code.
NUSE_Pipe_Blocking_Count [] - ce tableau de type
U8 contient des compteurs du nombre de tâches bloquées sur chaque canal. Ce tableau est créé uniquement si la prise en charge du verrouillage des tâches est activée.
Toutes ces structures de données sont initialisées avec des zéros par la fonction
NUSE_Init_Pipe () au démarrage de Nucleus SE. C'est logique, car tous les canaux sont créés vides (inutilisés). L'un des articles suivants contiendra une description complète des procédures de démarrage de Nucleus SE.
Voici les définitions de ces structures de données dans le fichier
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
Données utilisateur RAM
Il est de la responsabilité de l'utilisateur de fournir une zone de données en RAM pour stocker les données de chaque canal configuré. La taille de cette zone doit contenir un tableau de type
U8 , dans lequel tous les messages de canal s'adapteront.
Données ROM
La structure de ces données est la suivante:
NUSE_Pipe_Data [] est un tableau de type
ADDR qui a un enregistrement pour chaque canal configuré et indique la zone de données de chaque canal (voir la section "Données utilisateur en RAM" ci-dessus).
NUSE_Pipe_Size [] est un tableau de type
U8 , ayant une entrée pour chaque canal configuré et indiquant le nombre de messages pouvant tenir dans chaque canal.
NUSE_Pipe_Message_Size [] est un tableau de type
U8 qui a un enregistrement pour chaque canal configuré et montre la taille des messages (en octets) qui peuvent être placés sur chaque canal.
Ces structures de données sont déclarées et initialisées (statiquement) dans le fichier
nuse_config.c , ainsi:
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 ------ */ };
Mémoire des canaux
Comme tous les autres objets principaux de Nucleus SE, la quantité de mémoire nécessaire pour les canaux est prévisible.
La quantité de données dans la ROM (en octets) pour tous les canaux de l'application peut être calculée comme suit:
NUSE_PIPE_NUMBER * (taille de (ADDR) + 2)La quantité de données du noyau dans la RAM (en octets) pour tous les canaux d'application lorsque les tâches sont activées peut être calculée comme suit:
NUSE_PIPE_NUMBER * 4Sinon:
NUSE_PIPE_NUMBER * 3La quantité de données utilisateur en RAM (en octets) pour le canal avec l'index de
canal :
NUSE_Pipe_Size [pipe] * NUSE_Pipe_Message_Size [pipe]Appels d'API non réalisés
Quatre appels de service API Nucleus RTOS ne sont pas implémentés dans Nucleus SE.
Création de chaîne
Cet appel API crée un canal. Nucleus SE n'en a pas besoin car les canaux sont créés statiquement.
Prototype d'appel de service:
STATUS NU_Create_Pipe (NU_PIPE * pipe, CHAR * name, VOID * start_address, UNSIGNED pipe_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);Paramètres:
pipe - un pointeur vers le bloc de contrôle de canal fourni par l'utilisateur; il sera utilisé comme activateur de canal principal dans d'autres appels d'API;
nom - pointeur vers un nom de canal à 7 caractères avec un zéro de fin;
start_address - adresse de début de canal;
pipe_size - le nombre total d'octets dans le canal;
message_type - type de message pris en charge par le canal. Il peut prendre les valeurs
NU_FIXED_SIZE ou
NU_VARIABLE_SIZE ;
message_size - si le canal prend en charge les messages de longueur fixe, ce paramètre indique la taille exacte de chaque message. Sinon, si le canal prend en charge les messages de longueur variable, cette valeur sera la taille maximale du message;
suspend_type - Indique le type de suspension de tâche sur le canal. Il peut prendre les valeurs
NU_FIFO et
NU_PRIORITY (ordonnanceur FIFO et ordonnanceur
PRIORITY , respectivement).
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_PIPE - pointeur nul vers l'unité de contrôle de canal (
NULL ), ou l'unité de contrôle est déjà en cours d'utilisation;
NU_INVALID_MEMORY - une zone de données incorrecte a été spécifiée dans
start_address ;
NU_INVALID_MESSAGE - paramètre de type de
message non valide;
NU_INVALID_SIZE - soit la taille du message est supérieure à la taille du canal, soit la taille du canal ou du message est nulle;
NU_INVALID_SUSPEND - paramètre
suspend_type non
valide .
Supprimer la chaîne
Cet appel d'API supprime un canal créé précédemment. Nucleus SE n'en a pas besoin car les canaux sont créés statiquement et ne peuvent pas être supprimés.
Prototype d'appel de service:
STATUS NU_Delete_Pipe (NU_PIPE * pipe);Paramètres:
pipe - un pointeur vers un bloc de contrĂ´le de canal.
Valeur de retour:
NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_PIPE - pointeur de canal invalide.
Pointeurs de canal
Cet appel API crée une liste séquentielle de pointeurs vers tous les canaux du système. Dans Nucleus SE, ce n'est pas nécessaire, car les canaux sont identifiés par un simple index, pas un pointeur, par conséquent, une telle fonction serait redondante.
Prototype d'appel de service:
UNSIGNED NU_Pipe_Pointers (NU_PIPE ** pointer_list, UNSIGNED maximum_pointers);Paramètres:
pointer_list - un pointeur vers un tableau de pointeurs
NU_PIPE . Ce tableau sera rempli de pointeurs vers des canaux précédemment créés dans le système;
pointeurs maximum - le nombre maximum de pointeurs dans le tableau.
Valeur de retour:
Le nombre de pointeurs
NU_PIPE dans le tableau
Diffusion sur une chaîne
Cet appel d'API transmet le message à toutes les tâches en attente de messages provenant d'un canal spécifique. Dans Nucleus SE, cette fonctionnalité n'a pas été implémentée car elle ajoute une complexité redondante.
Prototype d'appel de service:
STATUS NU_Broadcast_To_Pipe (canal NU_PIPE *, message VOID *, taille UNSIGNED, suspension UNSIGNED);Paramètres:
pipe - un pointeur vers un bloc de contrĂ´le de canal;
message - pointeur vers le message transmis;
size - le nombre d'éléments de données
UNSIGNED dans le message. Si le canal prend en charge les messages de longueur variable, ce paramètre doit être égal ou inférieur à la taille du message pris en charge par le canal. Si le canal prend en charge les messages de longueur fixe, ce paramètre doit être exactement égal à la taille des messages pris en charge par le canal;
suspend - indique s'il faut suspendre la tâche appelante si le canal est déjà plein. 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_PIPE - pointeur non valide vers le canal;
NU_INVALID_POINTER - pointeur nul vers un message (
NULL );
NU_INVALID_SIZE - la taille de message spécifiée est incompatible avec la taille de message spécifiée lors de la création du canal;
NU_INVALID_SUSPEND - tentative de suspension à partir d'un thread non lié à une tâche;
NU_PIPE_FULL - il n'y a pas assez d'espace dans le canal pour le message;
NU_TIMEOUT - le canal est toujours plein, même après l'expiration du délai spécifié;
NU_PIPE_DELETED - le canal a été supprimé alors que la tâche a été suspendue;
NU_PIPE_RESET - Le canal a été réinitialisé alors que la tâche était 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 canaux ne font pas exception et, du point de vue de l'utilisateur, ils sont implémentés 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 (bloc de contrôle) qui a un type de données spécifique. Un pointeur vers cette unité de contrôle sert d'identifiant de canal. 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_PIPE comme l'équivalent de
U8 , une variable (pas un pointeur) de ce type sert d'identifiant de canal. 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 canaux. 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 canal peut être configuré pour traiter des messages composés d'un nombre arbitraire d'octets, tout comme Nucleus SE. Nucleus RTOS prend également en charge les canaux de messages de longueur variable pour lesquels seule la taille maximale des messages est spécifiée au moment de la création. Les messages de longueur variable ne sont pas pris en charge dans Nucleus SE.
Taille du canal
Dans Nucleus SE, le nombre maximal de messages par canal est de 256, car toutes les variables et constantes sont de type
U8 . Nucleuts RTOS n'a pas de telles limitations.
Appels d'API non réalisés
Nucleus RTOS prend en charge les frais généraux de dix canaux. Quatre d'entre eux ne sont pas implémentés dans Nucleus SE. Une description détaillée de ces appels, ainsi que les raisons de cette décision, se trouvent dans la section «Appels d'API non réalisés» plus haut dans cet article.
Dans l'article suivant, nous considérerons l'heure système.
À 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.