Die ganze Wahrheit über RTOS. Artikel Nr. 18. Ereignisflag-Gruppen: Hilfsdienste und Datenstrukturen



In diesem Artikel werden weiterhin Ereignisflaggruppen beschrieben.

Frühere Artikel in der Reihe:

Artikel Nr. 17. Ereignisflag-Gruppen: Einführung und Basisdienste
Artikel 16. Signale
Artikel Nr. 15. Speicherpartitionen: Dienste und Datenstrukturen
Artikel # 14. Speicherbereiche: Einführung und Grundversorgung
Artikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-Aufrufe
Artikel 12. Dienstleistungen für die Arbeit mit Aufgaben
Artikel 11. Aufgaben: Konfiguration und Einführung in die API
Artikel 10. Scheduler: Erweiterte Funktionen und Kontexterhaltung
Artikel 9. Scheduler: Implementierung
Artikel 8. Nucleus SE: Internes Design und Bereitstellung
Artikel 7. Nucleus SE: Einführung
Artikel 6. Andere RTOS-Dienste
Artikel 5. Aufgabeninteraktion und Synchronisation
Artikel 4. Aufgaben, Kontextwechsel und Interrupts
Artikel 3. Aufgaben und Planung
Artikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.


Event Flag Group Helper Services


Nucleus RTOS verfügt über drei API-Aufrufe, die Hilfsfunktionen für Ereignisflaggruppen bereitstellen: Abrufen von Gruppeninformationen, Abrufen von Informationen zur Anzahl der Ereignisflaggruppen in einer Anwendung und Abrufen von Zeigern auf alle Ereignisflaggruppen. Die ersten beiden Herausforderungen werden in Nucleus SE implementiert.

Abrufen von Ereignisflag-Gruppeninformationen


Dieser Dienstprogrammaufruf gibt Informationen über die Gruppe von Ereignisflags zurück. Die Implementierung dieses Aufrufs in Nucleus SE unterscheidet sich von der Implementierung in Nucleus RTOS darin, dass weniger Informationen zurückgegeben werden, da die Objektbenennung und die Reihenfolge der Aufgabenpause nicht unterstützt werden und die Aufgabenpause selbst deaktiviert werden kann.

Ein Aufruf zum Abrufen von Ereignisgruppeninformationen in Nucleus RTOS
Prototyp eines Serviceabrufs:
STATUS NU_Event_Group_Information (NU_EVENT_GROUP * Gruppe, CHAR * Name, UNSIGNED * Ereignisflags, UNSIGNED * Aufgaben_Warten, NU_TASK ** first_task);

Parameter:
group - ein Zeiger auf einen vom Benutzer bereitgestellten Steuerblock für eine Gruppe von Ereignisflags;
name - ein Zeiger auf den 8-stelligen Bereich für den Namen der Gruppe von Ereignisflags, einschließlich der abschließenden Null;
event_flags - Zeiger auf eine Variable, die den aktuellen Wert der angegebenen Gruppe von Ereignisflags annimmt.
task_waiting - ein Zeiger auf eine Variable, die die Anzahl der angehaltenen Aufgaben in dieser Gruppe von Ereignisflags übernimmt;
first_task - Ein Zeiger auf eine Variable vom Typ NU_TASK , der einen Zeiger auf die erste angehaltene Task nimmt.

Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_GROUP - ungültiger Zeiger auf eine Gruppe von Ereignisflags.

Ein Aufruf zum Abrufen von Ereignisgruppeninformationen in Nucleus SE
Dieser Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.

Prototyp eines Serviceabrufs:
STATUS NUSE_Event_Group_Information (Gruppe NUSE_EVENT_GROUP, U8 * Ereignisflags, U8 * Aufgaben_Warten, NUSE_TASK * Erste_Aufgabe);

Parameter:
Gruppe - Der Index der Gruppe von Ereignisflags, über die Informationen angefordert werden.
event_flags - Zeiger auf eine Variable, die den aktuellen Wert der angegebenen Gruppe von Ereignisflags annimmt.
task_waiting - Ein Zeiger auf eine Variable, die die Anzahl der angehaltenen Aufgaben in dieser Gruppe von Ereignisflags übernimmt (wenn die Aufgabe angehalten wird, wird nichts zurückgegeben).
first_task - Ein Zeiger auf eine Variable vom Typ NUSE_TASK , die den Index der ersten angehaltenen Aufgabe übernimmt (nichts wird zurückgegeben, wenn die Unterbrechung von Aufgaben deaktiviert ist).

Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_GROUP - Ungültiger Ereignisflag-Gruppenindex.

Implementierung von Ereignisgruppeninformationen in Nucleus SE
Die Implementierung dieses API-Aufrufs ist ziemlich einfach:

*event_flags = NUSE_Event_Group_Data[group]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Event_Group_Blocking_Count[group]; if (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)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif return NUSE_SUCCESS; 

Die Funktion gibt den Wert der Gruppe von Ereignisflags zurück. Wenn dann API-Aufrufe zum Blockieren von Aufgaben aktiviert werden, werden die Anzahl der ausstehenden Aufgaben und der Index der ersten zurückgegeben (andernfalls werden diese beiden Parameter auf Null gesetzt).

Abrufen der Anzahl der Ereignisflag-Gruppen


Dieser Dienstprogrammaufruf gibt die Anzahl der Ereignisflaggruppen in der Anwendung zurück. In Nucleus RTOS ändert sich dieser Wert im Laufe der Zeit, und der Rückgabewert zeigt die aktuelle Anzahl von Gruppen an, während in Nucleus SE dieser Wert während des Zusammenbaus bestimmt wird und sich nicht mit der Zeit ändert.

Aufrufen des Zählers von Ereignisflag-Gruppen in Nucleus RTOS
Prototyp eines Serviceabrufs:
UNSIGNED NU_Establised_Event_Groups (VOID);

Parameter:
Sind abwesend.

Rückgabewert:
Die aktuelle Anzahl der erstellten Ereignisflaggruppen.

Aufrufen des Zählers der Ereignisflag-Gruppen in Nucleus SE
Prototyp eines Serviceabrufs:
U8 NUSE_Event_Group_Count (void);

Parameter:
Sind abwesend.

Rückgabewert:
Die Anzahl der konfigurierten Ereignisflaggruppen.

Implementieren eines Ereignisflag-Gruppenzählers in Nucleus SE
Die Implementierung dieses API-Aufrufs ist ziemlich trivial: Der Wert des Symbols #define NUSE_EVENT_GROUP_NUMBER wird zurückgegeben .

Datenstrukturen


Wie alle anderen Nucleus SE-Objekte verwenden Ereignisflaggruppen ein oder zwei Arrays von Datenstrukturen (beide befinden sich im RAM). Die Größe der Arrays hängt von der Anzahl der in den Einstellungen definierten Gruppen ab.

Ich empfehle dringend, dass der Anwendungscode keinen direkten Zugriff auf diese Datenstrukturen verwendet, sondern über die bereitgestellten API-Funktionen auf sie verweist. Dies vermeidet Inkompatibilität mit zukünftigen Versionen von Nucleus SE und unerwünschte Nebenwirkungen und vereinfacht die Portierung der Anwendung auf Nucleus RTOS. Zum besseren Verständnis des Serviceabrufcodes und des Debuggens wird im Folgenden eine detaillierte Übersicht über die Datenstrukturen bereitgestellt.

RAM-Daten


Diese Daten haben folgende Struktur:
NUSE_Event_Group_Data [] - ein Array von Daten vom Typ U8 mit einem Datensatz für jede konfigurierte Gruppe von Flags; Es speichert Ereignisflag-Daten.
NUSE_Event_Group_Blocking_Count [] - Ein Array vom Typ U8, das einen Zähler für blockierte Aufgaben in jeder Gruppe von Ereignisflags enthält. Dieses Array ist nur vorhanden, wenn die Sperrfunktion in der API aktiviert ist.

Diese Datenstrukturen werden beim Start von Nucleus SE in der Funktion NUSE_Init_Event_Group () mit Nullen initialisiert. Einer der folgenden Artikel enthält eine vollständige Beschreibung der Startvorgänge von Nucleus SE.

Im Folgenden werden diese Datenstrukturen in der Datei nuse_init.c beschrieben :

 RAM U8 NUSE_Event_Group_Data[NUSE_EVENT_GROUP_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Event_Group_Blocking_Count[NUSE_EVENT_GROUP_NUMBER]; #endif 

ROM-Daten


Zum Implementieren von Gruppen von Ereignisflags werden keine Daten im ROM verwendet.

Speichergröße für Ereignisflaggruppen


Wie bei allen Nucleus SE-Kernelobjekten ist die für Ereignisflaggruppen erforderliche Speichermenge vorhersehbar.

Die Datenmenge im ROM für alle Gruppen von Ereignisflags in der Anwendung beträgt 0.

Die Speicherkapazität im RAM für alle Gruppen von Ereignisflags mit aktivierter API- Sperrfunktion beträgt NUSE_EVENT_GROUP_NUMBER * 2 .

Andernfalls ist es NUSE_EVENT_GROUP_NUMBER .

Nicht realisierte API-Aufrufe


Drei API-Aufrufe für Ereignisflaggruppen, die in Nucleus RTOS zu finden sind, wurden in Nucleus SE nicht implementiert.

Erstellen einer Ereignisflag-Gruppe


Dieser API-Aufruf erstellt eine Gruppe von Ereignisflags. Nucleus SE benötigt diesen Aufruf nicht, da Ereignisflaggruppen statisch erstellt werden.

Prototyp eines Serviceabrufs:
STATUS NU_Create_Event_Group (NU_EVENT_GROUP * Gruppe, CHAR * Name);

Parameter:

group - ein Zeiger auf einen vom Benutzer bereitgestellten Steuerblock für eine Gruppe von Ereignisflags; Wird als Deskriptor zum Verwalten von Gruppen von Ereignisflags in anderen API-Aufrufen verwendet
name - Ein Zeiger auf den 8-stelligen Namen der Gruppe von Ereignisflags mit einem abschließenden Nullbyte in diesem Bereich.

Rückgabewert:

NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_GROUP - Nullzeiger auf die Steuereinheit der Ereignisflaggruppe ( NULL ) oder bereits verwendet.

Löschen einer Gruppe von Ereignisflags


Dieser API-Aufruf entfernt die zuvor erstellte Ereignisflaggruppe. Nucleus SE benötigt diesen Aufruf nicht, da Ereignisflaggruppen statisch erstellt werden und nicht gelöscht werden können.

Prototyp eines Serviceabrufs:

STATUS NU_Delete_Event_Group (Gruppe NU_EVENT_GROUP *);

Parameter:

group - Ein Zeiger auf den Steuerblock der Gruppe von Ereignisflags.

Rückgabewert:

NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_GROUP - ungültiger Zeiger auf eine Gruppe von Ereignisflags.

Ereignisflaggengruppenzeiger


Dieser API-Aufruf erstellt eine sequentielle Liste von Zeigern auf alle Gruppen von Ereignisflags im System. Nucleus SE benötigt diesen Aufruf nicht, da Ereignisflaggruppen einfache Indizes und keine Zeiger haben.

Prototyp eines Serviceabrufs:

UNSIGNED NU_Event_Group_Pointers (NU_EVENT_GROUP * pointer_list, UNSIGNED maximum_pointers);

Parameter:

pointer_list - ein Zeiger auf ein Array von Zeigern NU_EVENT_GROUP . Dieses Array ist mit Zeigern auf Gruppen von Ereignisflags gefüllt, die im System erstellt wurden.
Maximum_Pointers - Die maximale Anzahl von Zeigern im Array.

Rückgabewert:

Die Anzahl der NU_EVENT_GROUP- Zeiger im Array.

Nucleus RTOS-kompatibel


Bei der Entwicklung von Nucleus SE war es mein Ziel, ein Höchstmaß an Codekompatibilität mit Nucleus RTOS sicherzustellen. Gruppen von Ereignisflags waren keine Ausnahme und werden aus Sicht des Entwicklers fast genauso implementiert wie in Nucleus RTOS. Es gibt einige Inkompatibilitäten, die ich für gültig gehalten habe, da der endgültige Code in Bezug auf die erforderliche Speichermenge verständlicher und effizienter wird. Andernfalls können Nucleus RTOS-API-Aufrufe fast direkt als Nucleus SE-Aufrufe verwendet werden.

Objektkennungen


In Nucleus RTOS werden alle Objekte durch Datenstrukturen (Steuereinheiten) eines bestimmten Typs beschrieben. Ein Zeiger auf diese Steuereinheit ist eine Kennung für eine Gruppe von Ereignisflags. Ich entschied, dass in Nucleus SE ein anderer Ansatz für eine effiziente Speichernutzung erforderlich ist: Alle Kernelobjekte werden durch mehrere Tabellen im RAM und / oder ROM beschrieben. Die Größe dieser Tabellen wird durch die Anzahl der konfigurierten Objekte jedes Typs bestimmt. Die Kennung eines bestimmten Objekts ist der Index in dieser Tabelle. Daher habe ich NUSE_EVENT_GROUP als Äquivalent zu U8 definiert . Eine Variable dieses Typs (kein Zeiger) dient als Kennung für eine Gruppe von Ereignisflags. Diese leichte Inkompatibilität ist leicht zu handhaben, wenn der Code von Nucleus SE nach Nucleus RTOS und umgekehrt portiert wird. In der Regel werden keine anderen Operationen an Objektkennungen als Verschieben und Speichern ausgeführt.

Nucleus RTOS unterstützt auch das Benennen von Ereignisflaggruppen. Diese Namen werden nur zum Debuggen verwendet. Ich habe sie von Nucleus SE ausgeschlossen, um Speicherplatz zu sparen.

Die Anzahl der Flags in der Gruppe


In Nucleus RTOS enthalten Ereignisflag-Gruppen jeweils 32 Flags, in Nucleus SE habe ich ihre Anzahl auf acht reduziert, da dies für einfache Anwendungen ausreicht und RAM spart. Nucleus SE kann leicht geändert werden, wenn größere Gruppen von Ereignisflags erforderlich sind.

Flag Absorptionsfunktion


Nucleus RTOS hat die Funktion, Ereignisflags nach dem Lesen zu löschen (zu absorbieren). Ich habe beschlossen, diese Funktion aus Nucleus SE auszuschließen, um das System zu vereinfachen, da das Absorbieren (Entfernen) von Flags erfolgt, wenn alle blockierten Aufgaben Flags zum Lesen erhalten haben, und dies schwierig zu implementieren wäre. Bei Bedarf kann eine Flag-Leseaufgabe diese jederzeit mithilfe eines separaten API-Aufrufs löschen.

Nicht realisierte API-Aufrufe


Nucleus RTOS unterstützt sieben Dienstprogrammaufrufe für die Arbeit mit Ereignisflaggruppen. Von diesen sind drei in Nucleus SE nicht implementiert. Die Details dieser Herausforderungen sowie die Entscheidung, sie von Nucleus SE auszuschließen, wurden oben beschrieben.
Der nächste Artikel befasst sich mit Semaphoren.

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

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


All Articles