Toute la vérité sur RTOS. Article # 17. Groupes de drapeaux d'événements: introduction et services de base



Des groupes de drapeaux d'événements ont déjà été mentionnés précédemment dans l'un des articles précédents (# 5). Dans Nucleus SE, ils sont similaires aux signaux, mais sont plus flexibles. Ils offrent un moyen peu coûteux et flexible de transférer des messages simples entre les tâches.


Articles précédents de la série:
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.


Utilisation de drapeaux d'événements


Dans Nucleus SE, les indicateurs d'événement sont définis pendant la phase de génération. Le nombre maximal de groupes d'indicateurs d'événements dans l'application est de 16. Si les groupes d'indicateurs d'événements ne sont pas définis, le code lié aux structures de données et aux appels de service des groupes d'indicateurs d'événements ne sera pas inclus dans l'application.

Groupe de drapeaux d'événements - un ensemble de drapeaux de huit bits, dont l'accès est réglementé afin que plusieurs tâches puissent utiliser en toute sécurité un drapeau. Une tâche peut définir ou effacer toute combinaison de drapeaux d'événements. Une autre tâche consiste à lire un groupe de drapeaux à tout moment, et il peut également attendre une certaine séquence de drapeaux (par sondage ou avec une pause).

Configuration des groupes d'indicateurs d'événements


Nombre de groupes d'indicateurs d'événements


Comme pour la plupart des objets Nucleus SE, la configuration des groupes d'indicateurs d'événements est spécifiée par les directives #define dans nuse_config.h . Le paramètre principal est NUSE_EVENT_GROUP_NUMBER , qui détermine le nombre de groupes d'indicateurs d'événements qui seront définis dans l'application. Par défaut, ce paramètre est défini sur 0 (c'est-à-dire que les groupes d'indicateurs d'événements ne sont pas utilisés) et peut avoir n'importe quelle valeur jusqu'à 16. Une valeur incorrecte entraînera une erreur de compilation, qui sera générée en archivant nuse_config_check.h (elle est activée par nuse_config.c , ce qui signifie qu'il compile avec ce module), par conséquent, la directive #error fonctionnera. La sélection d'une valeur différente de zéro est le principal activateur des groupes de drapeaux d'événements. Ce paramètre est utilisé lors de la définition des structures de données et leur taille dépend de sa valeur (plus d'informations à ce sujet dans les articles suivants). De plus, une valeur différente de zéro active les paramètres de l'API.

Activer les appels API


Chaque fonction API (appel d'utilitaire) dans Nucleus SE est activée par la directive #define dans nuse_config.h . Pour les groupes de drapeaux d'événements, ceux-ci incluent:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT

Par défaut, ils sont définis sur FALSE , désactivant ainsi chaque appel de service et bloquant l'inclusion de code qui les implémente. Pour configurer des groupes d'indicateurs d'événements, vous devez sélectionner les appels d'API nécessaires et définir les directives correspondantes sur TRUE .

Ce qui suit est un extrait du fichier nuse_config.h par défaut.

 #define NUSE_EVENT_GROUP_NUMBER 0 /* Number of event groups in the system - 0-16 */ #define NUSE_EVENT_GROUP_SET FALSE /* Service call enabler */ #define NUSE_EVENT_GROUP_RETRIEVE FALSE /* Service call enabler */ #define NUSE_EVENT_GROUP_INFORMATION FALSE /* Service call enabler */ #define NUSE_EVENT_GROUP_COUNT FALSE /* Service call enabler */ 

Une fonction API activée s'il n'y a pas de groupes d'indicateurs d'événements dans l'application entraînera une erreur de compilation (sauf pour NUSE_Event_Group_Count () , qui est toujours activé). Si votre code utilise un appel d'API qui n'a pas été activé, une erreur de mise en page se produira car le code d'implémentation n'a pas été inclus dans l'application.

Appels de l'utilitaire d'appel d'événement


Nucleus RTOS prend en charge sept appels d'utilitaires qui offrent les fonctionnalités suivantes:

  • DĂ©finissez des drapeaux d'Ă©vĂ©nements. Nucleus SE est implĂ©mentĂ© dans la fonction NUSE_Event_Group_Set () .
  • Lecture des drapeaux d'Ă©vĂ©nements. Dans Nucleus SE, implĂ©mentĂ© dans NUSE_Event_Group_Retrieve () .
  • Fournir des informations sur un groupe spĂ©cifique d'indicateurs d'Ă©vĂ©nements. Dans Nucleus SE, implĂ©mentĂ© dans NUSE_Event_Group_Information () .
  • Renvoie le nombre de groupes d'indicateurs d'Ă©vĂ©nements actuellement configurĂ©s dans l'application. Dans Nucleus SE, implĂ©mentĂ© dans NUSE_Event_Group_Count () .
  • Ajout d'un nouveau groupe d'indicateurs d'Ă©vĂ©nements Ă  l'application. Nucleus SE n'est pas implĂ©mentĂ©.
  • Suppression d'un groupe d'indicateurs d'Ă©vĂ©nements de l'application. Nucleus SE n'est pas implĂ©mentĂ©.
  • Renvoyer des pointeurs vers tous les groupes d'indicateurs d'Ă©vĂ©nements dans l'application. Nucleus SE n'est pas implĂ©mentĂ©.

La mise en œuvre de chacun de ces appels de surcharge est discutée en détail ci-dessous.

Il convient de noter qu'il n'y a pas de fonction de réinitialisation dans Nucleus RTOS ou Nucleus SE. Cela se fait intentionnellement. La fonction de réinitialisation implique la prévalence de l'état spécial des drapeaux. Pour les groupes de drapeaux d'événements, le seul état «spécial» est de réinitialiser tous les drapeaux, ce qui peut être fait en utilisant NUSE_Event_Group_Set () .

Appels de service pour la définition et la lecture de groupes d'indicateurs d'événements


Les opérations fondamentales qui peuvent être effectuées sur un groupe d'indicateurs d'événements sont la définition de la valeur d'un ou plusieurs indicateurs, ainsi que la lecture des valeurs d'indicateurs actuelles. Nucleus RTOS et Nucleus SE fournissent quatre appels d'API de base pour ces opérations.

Étant donné que les drapeaux d'événements sont des bits, ils sont mieux visualisés sous forme de nombres binaires. Étant donné que la norme C n'a historiquement pas pris en charge la représentation des constantes binaires (uniquement octales et hexadécimales), Nucleus SE possède un fichier d'en-tête utile nuse_binary.h qui contient des caractères #define comme b01010101 pour les 256 valeurs 8 bits.

Définir des indicateurs d'événement


L'appel de l'utilitaire Nucleus RTOS API pour le marquage est très flexible et vous permet de définir et d'effacer des valeurs de drapeau à l'aide d'opérations ET et OU . Nucleus SE offre des fonctionnalités similaires, mais la pause de tâche est facultative.

Appel à définir des indicateurs dans Nucleus RTOS
Prototype d'appel de service:

STATUS NU_Set_Events (groupe NU_EVENT_GROUP *, UNSIGNED event_flags, opération OPTION);

Paramètres:

group - un pointeur vers un bloc de contrôle fourni par l'utilisateur pour un groupe de drapeaux d'événements;
event_flags - valeur du masque de bits du groupe de drapeaux;
operation - l' opération à effectuer, NU_OR (pour définir les indicateurs) ou NU_AND (pour effacer les indicateurs).

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_INVALID_GROUP - pointeur non valide vers un groupe de drapeaux d'événements;
NU_INVALID_OPERATION - L'opération spécifiée est différente de NU_OR et NU_AND .

Appel à définir des drapeaux dans Nucleus SE
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:

STATUS NUSE_Event_Group_Set (groupe NUSE_EVENT_GROUP, U8 event_flags, opération OPTION);

Paramètres:

group - l'index (ID) du groupe d'événements dont les indicateurs sont définis / effacés;
event_flags - valeur du bit maxi d'un groupe de drapeaux;
operation - l' opération à effectuer, NUSE_OR (pour définir les drapeaux) ou NUSE_AND (pour effacer les drapeaux).

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_INVALID_GROUP - index non valide d'un groupe de drapeaux d'événements;
NUSE_INVALID_OPERATION - L'opération spécifiée est différente de NUSE_OR et NUSE_AND .

Implémentation de l'installation de drapeaux d'événements dans Nucleus SE
Le code initial de la fonction d'API NUSE_Event_Group_Set () est général (après vérification des paramètres), que l'API prenne en charge les appels de blocage (suspendre les tâches) ou non. La logique est assez simple:

 NUSE_CS_Enter(); if (operation == NUSE_OR) { NUSE_Event_Group_Data[group] |= event_flags; } else /* NUSE_AND */ { NUSE_Event_Group_Data[group] &= event_flags; } 

Le masque de bits event_flags est superposé (à l'aide de l'opération AND ou OR ) sur la valeur du groupe sélectionné de drapeaux d'événements.

Le code restant n'est activé que lorsque le verrouillage des tâches est activé:

 #if NUSE_BLOCKING_ENABLE while (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this event group */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_EVENT_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == group)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Event_Group_Blocking_Count[group]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif #endif NUSE_CS_Exit(); return NUSE_SUCCESS; 

Si des tâches sont suspendues (pour lecture) à partir de ce groupe d'indicateurs, elles reprennent. Lorsqu'ils ont la possibilité de poursuivre l'exécution (cela dépend de l'ordonnanceur), ils peuvent déterminer si les conditions de leur reprise sont remplies ou non (voir lecture des drapeaux d'événements).

Lecture des drapeaux d'événements


Les appels à la lecture de l'utilitaire Nucleus RTOS API sont très flexibles et vous permettent de suspendre les tâches indéfiniment ou avec un délai d'expiration spécifique si l'opération ne peut pas être terminée immédiatement (par exemple, si vous essayez de lire une séquence spécifique d'indicateurs d'événements qui ne représente pas l'état actuel). Nucleus SE offre les mêmes fonctionnalités, seule la pause de tâche est facultative et le délai d'attente n'est pas implémenté.

Défi des drapeaux dans Nucleus RTOS
Prototype d'appel de service:

STATUS NU_Retrieve_Events (groupe NU_EVENT_GROUP *, UNSIGNED required_events, opération OPTION, UNSIGNED * retrieved_events, UNSIGNED suspend);

Paramètres:

group - un pointeur vers un bloc de contrôle fourni par l'utilisateur pour un groupe de drapeaux d'événements;
required_events - un masque de bits qui définit les drapeaux à lire;
opération - quatre opérations sont disponibles: NU_AND , NU_AND_CONSUME , NU_OR et NU_OR_CONSUME . Les opérations NU_AND et NU_AND_CONSUME indiquent que tous les indicateurs demandés sont requis. Les opérations NU_OR et NU_OR_CONSUME indiquent qu'un ou plusieurs des fanions demandés sont suffisants. Le paramètre CONSUME efface automatiquement les indicateurs existants après une requête réussie;
retrieved_events - pointeur de stockage pour les valeurs des drapeaux d'événements lus;
suspend - spécification pour suspendre les tâches; peut prendre les valeurs NU_NO_SUSPEND ou NU_SUSPEND , ou la valeur de timeout en ticks du temporisateur système (de 1 à 4 294 967 293).

Valeur de retour:

NU_SUCCESS - l'appel s'est terminé avec succès;
NU_NOT_PRESENT - l'opération spécifiée n'a pas renvoyé d'événements (pas un seul événement dans le cas de NU_OR et pas tous les événements dans le cas de NU_AND);
NU_INVALID_GROUP - pointeur non valide vers un groupe de drapeaux d'événements;
NU_INVALID_OPERATION - l'opération spécifiée était incorrecte;
NU_INVALID_POINTER - pointeur nul vers le magasin de drapeaux d'événements (NULL);
NU_INVALID_SUSPEND - tentative de pause à partir d'un thread non lié à une tâche;
NU_TIMEOUT - la combinaison requise de drapeaux d'événements n'a pas été définie même après le délai spécifié;
NU_GROUP_DELETED - le groupe d'indicateurs d'événements a été supprimé alors que la tâche était suspendue.

Défi des drapeaux dans Nucleus SE
Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:

STATUS NUSE_Event_Group_Retrieve (groupe NUSE_EVENT_GROUP, U8 request_events, opération OPTION, U8 * retrieved_events, U8 suspend);

Paramètres:

groupe - index (ID) du groupe lu d'indicateurs d'événement;
required_events - un masque de bits qui définit les drapeaux à lire;
opération - une spécification indiquant le nombre de drapeaux nécessaires: NUSE OR (certains drapeaux) ou NUSE AND (tous les drapeaux);
retrieved_events - un pointeur vers le magasin pour les valeurs réelles des drapeaux d'événements lus (avec l'opération NUSE_AND, ce sera le même que celui transmis dans le paramètre required_events );
suspend - spécification pour suspendre la tâche, peut prendre les valeurs NUSE_NO_SUSPEND ou NUSE_SUSPEND .

Valeur de retour:

NUSE_SUCCESS - l'appel s'est terminé avec succès;
NUSE_NOT_PRESENT - l'opération spécifiée n'a pas renvoyé d'événements (pas un seul événement dans le cas de NUSE_OR et pas tous les événements dans le cas de NUSE_AND );
NUSE_INVALID_GROUP - index non valide d'un groupe de drapeaux d'événements;
NUSE_INVALID_OPERATION - l'opération spécifiée est différente de NUSE_OR ou NUSE_AND ;
NUSE_INVALID_POINTER - un pointeur nul vers le magasin de drapeaux d'événements lus ( NULL );
NUSE_INVALID_SUSPEND - une tentative de pause à partir d'un flux non-tâche ou lorsque la prise en charge du blocage des appels d'API est désactivée.

Implémentation de la lecture des drapeaux d'événements dans Nucleus SE
La version du code de fonction API NUSE_Event_Group_Retrieve () (après vérification des paramètres) est sélectionnée lors de la compilation conditionnelle selon que la prise en charge des appels API pour bloquer (suspendre) les tâches est activée ou non. Examinons ces deux options séparément.

Si le verrou est désactivé, le code complet de cet appel API ressemblera à ceci:

 temp_events = NUSE_Event_Group_Data[group] & requested_events; if (operation == NUSE_OR) { if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } else /* operation == NUSE_AND */ { if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } 

Les indicateurs d'événement requis sont sélectionnés dans le groupe d'indicateurs d'événement spécifié. La valeur est comparée aux événements requis, en tenant compte de l'opération ET / OU , ainsi que du résultat renvoyé et des valeurs immédiates des drapeaux demandés.

Si le verrouillage des tâches est activé, le code devient plus complexe:

 do { temp_events = NUSE_Event_Group_Data[group] & requested_events; if (operation == NUSE_OR) { if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } else /* operation == NUSE_AND */ { if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } if (return_value == NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_SUSPEND) /* block task */ { NUSE_Event_Group_Blocking_Count[group]++; NUSE_Suspend_Task(NUSE_Task_Active, (group << 4) | NUSE_EVENT_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND); 

Le code est placé dans une boucle do ... while , qui fonctionne lorsque le paramètre suspend est NUSE_SUSPEND .

Les drapeaux d'événements demandés sont lus comme s'ils étaient appelés sans blocage. Si la lecture échoue et que le paramètre de suspension est NUSE_NO_SUSPEND , l'appel d'API est défini sur NUSE_NOT_PRESENT . Si le paramètre suspend a été défini sur NUSE_SUSPEND , la tâche se met en pause. Lors du retour (lorsque la tâche reprend), si la valeur de retour est NUSE_SUCCESS , indiquant que la tâche a été reprise car les indicateurs d'événement de ce groupe ont été définis ou effacés, le cycle recommence depuis le début, les indicateurs sont lus et vérifiés. Puisqu'il n'y a pas de fonction API pour réinitialiser les groupes d'indicateurs d'événements, c'est la seule raison pour que la tâche reprenne, mais le processus de vérification NUSE_Task_Blocking_Return [] a été laissé sur le système pour la compatibilité du contrôle de verrouillage avec d'autres types d'objets.

L'article suivant décrit les appels d'API supplémentaires associés aux groupes d'indicateurs d'événements, ainsi que leurs structures 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.

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


All Articles