
Gruppen von Ereignisflags wurden bereits in einem der vorherigen Artikel (Nr. 5) erwähnt. In Nucleus SE ähneln sie Signalen, sind jedoch flexibler. Sie bieten eine kostengünstige und flexible Möglichkeit, einfache Nachrichten zwischen Aufgaben zu übertragen.
Frühere Artikel in der Reihe:
Artikel 16. SignaleArtikel Nr. 15. Speicherpartitionen: Dienste und DatenstrukturenArtikel # 14. Speicherbereiche: Einführung und GrundversorgungArtikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-AufrufeArtikel 12. Dienstleistungen für die Arbeit mit AufgabenArtikel 11. Aufgaben: Konfiguration und Einführung in die APIArtikel 10. Scheduler: Erweiterte Funktionen und KontexterhaltungArtikel 9. Scheduler: ImplementierungArtikel 8. Nucleus SE: Internes Design und BereitstellungArtikel 7. Nucleus SE: EinführungArtikel 6. Andere RTOS-DiensteArtikel 5. Aufgabeninteraktion und SynchronisationArtikel 4. Aufgaben, Kontextwechsel und InterruptsArtikel 3. Aufgaben und PlanungArtikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.
Ereignisflags verwenden
In Nucleus SE werden Ereignisflags während der Erstellungsphase definiert. Die maximale Anzahl von Ereignisflaggruppen in der Anwendung beträgt 16. Wenn keine Ereignisflaggruppen definiert sind, wird der Code, der sich auf die Datenstrukturen und Serviceaufrufe der Ereignisflaggruppen bezieht, nicht in die Anwendung aufgenommen.
Gruppe von Ereignisflags - Ein Satz von 8-Bit-Flags, auf die der Zugriff so geregelt ist, dass mehrere Aufgaben ein Flag sicher verwenden können. Eine Aufgabe kann eine beliebige Kombination von Ereignisflags setzen oder löschen. Eine andere Aufgabe besteht darin, jederzeit eine Gruppe von Flags zu lesen, und sie kann auch auf eine bestimmte Folge von Flags warten (durch Abfrage oder mit einer Pause).
Ereignisflaggruppen konfigurieren
Anzahl der Ereignisflaggruppen
Wie bei den meisten Nucleus SE-Objekten wird die Konfiguration von Ereignisflaggruppen durch die Direktiven
#define in
nuse_config.h festgelegt . Der Hauptparameter ist
NUSE_EVENT_GROUP_NUMBER , der bestimmt, wie viele Gruppen von Ereignisflags in der Anwendung definiert werden. Standardmäßig ist dieser Parameter auf 0 gesetzt (
dh Gruppen von Ereignisflags werden nicht verwendet) und kann einen beliebigen Wert von bis zu 16 haben. Ein falscher Wert führt zu einem Kompilierungsfehler, der durch Einchecken von
nuse_config_check.h generiert wird (aktiviert durch
nuse_config.c) Dies bedeutet, dass es mit diesem Modul kompiliert wird. Infolgedessen
funktioniert die Direktive
#error . Die Auswahl eines Werts ungleich Null dient als Hauptaktivator für die Ereignisflaggruppen. Dieser Parameter wird beim Definieren von Datenstrukturen verwendet und ihre Größe hängt von ihrem Wert ab (mehr dazu in den folgenden Artikeln). Darüber hinaus aktiviert ein Wert ungleich Null die API-Einstellungen.
API-Aufrufe aktivieren
Jede API-Funktion (Dienstprogrammaufruf) in Nucleus SE wird durch die Direktive
#define in
nuse_config.h aktiviert. Für Gruppen von Ereignisflags gehören dazu:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT
Standardmäßig sind sie auf
FALSE gesetzt , wodurch jeder Serviceabruf deaktiviert und die Aufnahme von Code blockiert wird, der sie implementiert. Um Gruppen von Ereignisflags zu konfigurieren, müssen Sie die erforderlichen API-Aufrufe auswählen und die entsprechenden Anweisungen auf
TRUE setzen .
Das Folgende ist ein Auszug aus der Standarddatei nuse_config.h.
#define NUSE_EVENT_GROUP_NUMBER 0 #define NUSE_EVENT_GROUP_SET FALSE #define NUSE_EVENT_GROUP_RETRIEVE FALSE #define NUSE_EVENT_GROUP_INFORMATION FALSE #define NUSE_EVENT_GROUP_COUNT FALSE
Eine aktivierte API-Funktion, wenn keine Ereignisflaggruppen in der Anwendung vorhanden sind, führt zu einem Kompilierungsfehler (mit Ausnahme von
NUSE_Event_Group_Count () , das immer aktiviert ist). Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, tritt ein Layoutfehler auf, da der Implementierungscode nicht in der Anwendung enthalten war.
Ereignisaufruf-Dienstprogrammaufrufe
Nucleus RTOS unterstützt sieben Dienstprogrammaufrufe mit den folgenden Funktionen:
- Setzen Sie Ereignisflags. Nucleus SE ist in der Funktion NUSE_Event_Group_Set () implementiert.
- Ereignisflags lesen. In Nucleus SE, implementiert in NUSE_Event_Group_Retrieve () .
- Bereitstellung von Informationen zu einer bestimmten Gruppe von Ereignisflags. In Nucleus SE, implementiert in NUSE_Event_Group_Information () .
- Gibt die Anzahl der aktuell konfigurierten Ereignisflaggruppen in der Anwendung zurück. In Nucleus SE, implementiert in NUSE_Event_Group_Count () .
- Hinzufügen einer neuen Gruppe von Ereignisflags zur Anwendung. Nucleus SE ist nicht implementiert.
- Entfernen einer Gruppe von Ereignisflags aus der Anwendung. Nucleus SE ist nicht implementiert.
- Rückgabe von Zeigern auf alle Gruppen von Ereignisflags in der Anwendung. Nucleus SE ist nicht implementiert.
Die Implementierung jedes dieser Overhead-Aufrufe wird nachstehend ausführlich erläutert.
Es ist erwähnenswert, dass weder in Nucleus RTOS noch in Nucleus SE eine Rücksetzfunktion vorhanden ist. Dies geschieht absichtlich. Die Rücksetzfunktion impliziert die Prävalenz des Sonderzustands der Flags. Für Gruppen von Ereignisflags besteht der einzige "spezielle" Status darin, alle Flags zurückzusetzen, was mit
NUSE_Event_Group_Set () erfolgen kann .
Serviceaufrufe zum Setzen und Lesen von Ereignisflaggruppen
Die grundlegenden Operationen, die für eine Gruppe von Ereignisflags ausgeführt werden können, sind das Setzen des Werts eines oder mehrerer Flags sowie das Lesen der aktuellen Flagwerte. Nucleus RTOS und Nucleus SE bieten vier grundlegende API-Aufrufe für diese Vorgänge.
Da Ereignisflags Bits sind, werden sie am besten als Binärzahlen dargestellt. Da Standard C die Darstellung von
Binärkonstanten (nur oktal und hexadezimal) in der
Vergangenheit nicht unterstützt hat, verfügt Nucleus SE über eine nützliche Header-Datei
nuse_binary.h , die
# define- Zeichen wie
b01010101 für alle 256 8-Bit-Werte enthält.
Ereignisflags setzen
Der Aufruf des Nucleus RTOS API-Dienstprogramms zum Kennzeichnen ist sehr flexibel und ermöglicht das Festlegen und Löschen von Kennzeichnungswerten mithilfe von
UND- und
ODER- Operationen. Nucleus SE bietet ähnliche Funktionen, die Unterbrechung der Aufgabe ist jedoch optional.
Aufruf zum Setzen von Flags in Nucleus RTOSPrototyp eines Serviceabrufs:
STATUS NU_Set_Events (Gruppe NU_EVENT_GROUP *, UNSIGNED event_flags, OPTION-Operation);Parameter:
group - ein Zeiger auf einen vom Benutzer bereitgestellten Steuerblock für eine Gruppe von Ereignisflags;
event_flags - Wert der Bitmaske der
Flaggruppe ;
Operation - Die
auszuführende Operation ,
NU_OR (zum Setzen von Flags) oder
NU_AND (zum Löschen von Flags).
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_GROUP - ungültiger Zeiger auf eine Gruppe von Ereignisflags;
NU_INVALID_OPERATION - Die angegebene Operation unterscheidet sich von
NU_OR und
NU_AND .
Aufruf zum Setzen von Flags in Nucleus SEDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Event_Group_Set (Gruppe NUSE_EVENT_GROUP, U8 event_flags, OPTION-Operation);Parameter:
Gruppe - der Index (ID) der Ereignisgruppe, deren Flags gesetzt / gelöscht sind;
event_flags - Wert des
Bitmaxi einer Gruppe von Flags;
Operation - Die
auszuführende Operation ,
NUSE_OR (zum Setzen von Flags) oder
NUSE_AND (zum Löschen von Flags).
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_GROUP - ungültiger Index einer Gruppe von Ereignisflags;
NUSE_INVALID_OPERATION - Die angegebene Operation unterscheidet sich von
NUSE_OR und
NUSE_AND .
Implementierung der Installation von Ereignisflags in Nucleus SEDer Anfangscode der API-Funktion
NUSE_Event_Group_Set () ist allgemein (nach Überprüfung der Parameter), unabhängig davon, ob die API das Blockieren von Aufrufen unterstützt (Task-Suspendierung) oder nicht. Die Logik ist ziemlich einfach:
NUSE_CS_Enter(); if (operation == NUSE_OR) { NUSE_Event_Group_Data[group] |= event_flags; } else /* NUSE_AND */ { NUSE_Event_Group_Data[group] &= event_flags; }
Die
Bitmaske event_flags wird (unter Verwendung der
UND- oder
ODER- Verknüpfung) dem Wert der ausgewählten Gruppe von Ereignisflags überlagert.
Der verbleibende Code wird nur aktiviert, wenn die Task-Sperre aktiviert ist:
#if NUSE_BLOCKING_ENABLE while (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; 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;
Wenn Aufgaben (zum Lesen) von dieser Gruppe von Flags angehalten werden, werden sie fortgesetzt. Wenn sie die Möglichkeit erhalten, die Ausführung fortzusetzen (dies hängt vom Scheduler ab), können sie feststellen, ob die Bedingungen für ihre Wiederaufnahme erfüllt sind oder nicht (siehe Lesen von Ereignisflags).
Ereignisflags lesen
Die Aufrufe des Nucleus RTOS API-Dienstprogramms zum Lesen sind sehr flexibel und ermöglichen es Ihnen, Aufgaben auf unbestimmte Zeit oder mit einem bestimmten Zeitlimit anzuhalten, wenn der Vorgang nicht sofort abgeschlossen werden kann (z. B. wenn Sie versuchen, eine bestimmte Folge von Ereignisflags zu lesen, die nicht den aktuellen Status darstellen). Nucleus SE bietet dieselben Funktionen, nur die Unterbrechung der Aufgabe ist optional und das Zeitlimit ist nicht implementiert.
Flags Challenge in Nucleus RTOSPrototyp eines Serviceabrufs:
STATUS NU_Retrieve_Events (Gruppe NU_EVENT_GROUP *, UNSIGNED Requested_events, OPTION-Operation, UNSIGNED * Retrieved_events, UNSIGNED Suspend);Parameter:
group - ein Zeiger auf einen vom Benutzer bereitgestellten Steuerblock für eine Gruppe von Ereignisflags;
request_events - eine Bitmaske, die die zu lesenden Flags definiert;
Operation - Es stehen vier
Operationen zur Verfügung:
NU_AND ,
NU_AND_CONSUME ,
NU_OR und
NU_OR_CONSUME . Die Operationen
NU_AND und
NU_AND_CONSUME geben an, dass alle angeforderten Flags erforderlich sind. Die Operationen
NU_OR und
NU_OR_CONSUME zeigen an, dass eines oder mehrere der angeforderten Flags ausreichend sind. Der Parameter
CONSUME löscht nach einer erfolgreichen Anforderung automatisch vorhandene Flags.
retrieved_events - Speicherzeiger für die Werte der Leseereignisflags;
suspend - Spezifikation für das Anhalten von Aufgaben; kann die Werte
NU_NO_SUSPEND oder
NU_SUSPEND oder den Timeout-Wert in Takt-
Ticks (von 1 bis 4.294.967.293)
annehmen .
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_NOT_PRESENT - Die angegebene Operation hat keine Ereignisse zurückgegeben (kein einziges Ereignis im Fall von NU_OR und nicht alle Ereignisse im Fall von NU_AND).
NU_INVALID_GROUP - ungültiger Zeiger auf eine Gruppe von Ereignisflags;
NU_INVALID_OPERATION - Die angegebene Operation war falsch.
NU_INVALID_POINTER - Nullzeiger auf den Speicher der Ereignisflags (NULL);
NU_INVALID_SUSPEND - Versuch, von einem nicht aufgabenbezogenen Thread aus
anzuhalten ;
NU_TIMEOUT - Die erforderliche Kombination von Ereignisflags wurde auch nach dem angegebenen Zeitlimit nicht gesetzt.
NU_GROUP_DELETED - Die Gruppe von Ereignisflags wurde gelöscht, während die Aufgabe angehalten wurde.
Flags Challenge in Nucleus SEDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Event_Group_Retrieve (Gruppe NUSE_EVENT_GROUP, U8 angeforderte_Ereignisse, OPTION-Operation, U8 * abgerufene_Ereignisse, U8-Suspend);Parameter:
Gruppe - Index (ID) der gelesenen Gruppe von Ereignisflags;
request_events - eine Bitmaske, die die zu lesenden Flags definiert;
operation - eine Spezifikation, die die Anzahl der benötigten Flags
angibt :
NUSE OR (einige Flags) oder
NUSE AND (alle Flags);
retrieved_events - ein Zeiger auf den Speicher für die tatsächlichen Werte der
Leseereignisflags (bei der Operation
NUSE_AND entspricht dies der
Übergabe im Parameter
request_events );
suspend - Spezifikation zum Anhalten einer Aufgabe, die die Werte
NUSE_NO_SUSPEND oder
NUSE_SUSPEND annehmen kann .
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_NOT_PRESENT - Die angegebene Operation hat keine Ereignisse zurückgegeben (kein einziges Ereignis im Fall von
NUSE_OR und nicht alle Ereignisse im Fall von
NUSE_AND ).
NUSE_INVALID_GROUP - ungültiger Index einer Gruppe von Ereignisflags;
NUSE_INVALID_OPERATION - Die angegebene Operation unterscheidet sich von
NUSE_OR oder
NUSE_AND .
NUSE_INVALID_POINTER - ein Nullzeiger auf den Speicher der
Leseereignisflags (
NULL );
NUSE_INVALID_SUSPEND - Ein Versuch, eine Pause von einem Nicht-Task-Flow
einzulegen oder wenn die Unterstützung für das Blockieren von API-Aufrufen deaktiviert ist.
Implementieren des Lesens von Ereignisflags in Nucleus SEDie Version des API-Funktionscodes
NUSE_Event_Group_Retrieve () (nach Überprüfung der Parameter) wird während der bedingten Kompilierung ausgewählt, je nachdem, ob die Unterstützung für die API-Aufrufe zum Blockieren (Anhalten) von Aufgaben aktiviert ist oder nicht. Betrachten wir diese beiden Optionen getrennt.
Wenn die Sperre deaktiviert ist, sieht der vollständige Code für diesen API-Aufruf folgendermaßen aus:
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; } }
Die erforderlichen Ereignisflags werden aus der angegebenen Ereignisflaggruppe ausgewählt. Der Wert wird unter Berücksichtigung der
UND / ODER- Operation sowie des zurückgegebenen Ergebnisses und der unmittelbaren Werte der angeforderten Flags mit den erforderlichen Ereignissen verglichen.
Wenn die Task-Sperre aktiviert ist, wird der Code komplexer:
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 { 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) { 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);
Der Code wird in eine
do ... while-Schleife eingefügt , die funktioniert, während der
suspend- Parameter
NUSE_SUSPEND lautet .
Die angeforderten Ereignisflags werden so gelesen, als würden sie ohne Blockierung aufgerufen. Wenn der
Lesevorgang nicht erfolgreich ist und der
Suspend- Parameter
NUSE_NO_SUSPEND lautet , wird der API-Aufruf auf
NUSE_NOT_PRESENT gesetzt . Wenn der
Suspend- Parameter auf
NUSE_SUSPEND gesetzt wurde , wird die Task
angehalten . Wenn bei der Rückkehr (wenn die Aufgabe
fortgesetzt wird) der Rückgabewert
NUSE_SUCCESS lautet und
angibt , dass die Aufgabe fortgesetzt wurde, weil die Ereignisflags in dieser Gruppe gesetzt oder gelöscht wurden, beginnt der Zyklus von
vorne , die Flags werden gelesen und überprüft. Da es keine API-Funktion zum Zurücksetzen von Ereignisflaggruppen gibt, ist dies der einzige Grund für die Wiederaufnahme der Aufgabe. Der Überprüfungsprozess
NUSE_Task_Blocking_Return [] wurde jedoch auf dem System belassen, um die Kompatibilität der
Sperrsteuerung mit anderen
Objekttypen zu gewährleisten.
Der folgende Artikel beschreibt zusätzliche API-Aufrufe, die Ereignisflaggruppen zugeordnet sind, sowie deren Datenstrukturen.
Über den Autor: Colin Walls ist seit über dreißig Jahren in der Elektronikindustrie tätig und widmet sich die meiste Zeit der Firmware. Heute ist er Firmware-Ingenieur bei Mentor Embedded (einer Abteilung von Mentor Graphics). Colin Walls spricht häufig auf Konferenzen und Seminaren, Autor zahlreicher technischer Artikel und zweier Bücher über Firmware. Lebt in Großbritannien.
Colins professioneller
Blog , E-Mail: colin_walls@mentor.com.