
Postfächer wurden in einem der vorherigen Artikel (Nr. 5) erwähnt. Sie sind die zweitleichteste von Nucleus SE unterstützte Signal-zu-Signal-Inter-Tasking-Kommunikationsmethode und bieten eine kostengünstige und flexible Möglichkeit, einfache Nachrichten zwischen Aufgaben zu übertragen.
Frühere Artikel in der Reihe:
Artikel Nr. 20. Semaphoren: Nebendienstleistungen und DatenstrukturenArtikel Nr. 19. Semaphoren: Einführung und GrundversorgungArtikel Nr. 18. Ereignisflag-Gruppen: Hilfsdienste und DatenstrukturenArtikel Nr. 17. Ereignisflag-Gruppen: Einführung und BasisdiensteArtikel 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.
Verwenden von Postfächern
In Nucleus SE werden Postfächer während der Erstellungsphase definiert. Eine Anwendung kann bis zu 16 Postfächer haben. Wenn die Anwendung keine Postfächer hat, werden der mit den Postfächern verknüpfte Serviceanrufcode und die Datenstrukturen nicht in die Anwendung aufgenommen.
Ein Postfach ist nur ein Ort zum Speichern von Daten, deren Größe ausreicht, um eine Variable vom Typ
ADDR zu speichern, und deren sicherer Zugriff so gesteuert wird, dass mehrere Aufgaben sie verwenden können. Eine Aufgabe kann Daten an eine Mailbox senden. Infolgedessen wird das Postfach voll, und keine Aufgabe kann Daten an das Postfach senden, bis eine Aufgabe den Vorgang des Lesens des Postfachs ausführt oder bis das Postfach leer ist. Der Versuch, Daten an ein vollständiges Postfach zu senden oder ein leeres Postfach zu lesen, führt je nach den ausgewählten API-Aufrufeinstellungen und der Nucleus SE-Konfiguration zu einem Fehler oder einer Aufgabenpause.
Postfächer und Warteschlangen
In einigen Implementierungen des Betriebssystems werden Postfächer nicht implementiert. Alternativ wird vorgeschlagen, eine Warteschlange zu verwenden. Dies klingt logisch, da eine solche Warteschlange dieselbe Funktionalität wie ein Postfach bietet. Die Warteschlange ist jedoch eine komplexere Datenstruktur und enthält viel mehr Hilfsdaten, Code und eine längere Servicezeit.
In Nucleus SE können Sie wie in Nucleus RTOS jeden dieser Objekttypen auswählen.
Wenn Ihre Anwendung mehrere Warteschlangen und ein Postfach hat, ist es sinnvoll, das Postfach durch eine Warteschlange zu ersetzen. Dadurch wird der Overhead geringfügig erhöht, der gesamte mit Postfächern verknüpfte API-Code wird jedoch entfernt. Alternativ können Sie die Anwendung mit beiden Methoden konfigurieren und die Datenmenge und Leistung vergleichen.
Warteschlangen werden in zukünftigen Artikeln behandelt.
Postfächer konfigurieren
Anzahl der Postfächer
Wie bei den meisten Nucleus SE-Objekten wird die Postfachkonfiguration hauptsächlich durch die Direktiven
#define in der Datei
nuse_config.h definiert . Der Hauptparameter ist
NUSE_MAILBOX_NUMBER , der die Anzahl der Postfächer in der Anwendung bestimmt. Der Standardwert ist Null (
dh es gibt keine Postfächer) und kann Werte bis zu 16 annehmen. Ein falscher Wert führt zu einem Fehler beim Kompilieren, der durch Einchecken von
nuse_config_check.h generiert wird (er ist in der Datei
nuse_config.c enthalten und wird damit kompiliert ), wodurch die Direktive
#error ausgelöst wird .
Die Auswahl eines Werts ungleich Null ist der Hauptaktivator für Postfächer. Dieser Parameter wird beim Definieren von Datenstrukturen verwendet und ihre Größe hängt von ihrem Wert ab (mehr dazu im nächsten Artikel). 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 der Datei
nuse_config.h aktiviert. Für Postfächer sind diese Anweisungen:
NUSE_MAILBOX_SEND NUSE_MAILBOX_RECEIVE NUSE_MAILBOX_RESET NUSE_MAILBOX_INFORMATION NUSE_MAILBOX_COUNT
Standardmäßig sind sie auf
FALSE gesetzt , wodurch alle Serviceaufrufe deaktiviert und die Aufnahme von Code blockiert werden, der sie implementiert. Um Postfächer in der Anwendung zu konfigurieren, müssen Sie die erforderlichen API-Aufrufe auswählen und auf
TRUE setzen .
Das Folgende ist ein Codeabschnitt aus der Datei
nuse_config.h .
/* Number of mailboxes in the system - 0-16 */ #define NUSE_MAILBOX_NUMBER 0 /* Service call enablers: */ #define NUSE_MAILBOX_SEND FALSE #define NUSE_MAILBOX_RECEIVE FALSE #define NUSE_MAILBOX_RESET FALSE #define NUSE_MAILBOX_INFORMATION FALSE #define NUSE_MAILBOX_COUNT FALSE
Wenn die Postfach-API-Funktion aktiviert ist und die Anwendung keine Postfächer enthält (mit Ausnahme von
NUSE_Mailbox_Count () , das immer aktiviert ist), tritt ein Kompilierungsfehler auf. Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, tritt ein Layoutfehler auf, da der Implementierungscode nicht in der Anwendung enthalten war.
Postfachdienstanrufe
Nucleus RTOS unterstützt neun Serviceanrufe, die Postfächern zugeordnet sind und die folgenden Funktionen bieten:
- Senden von Nachrichten an die Mailbox. Nucleus SE ist in der Funktion NUSE_Mailbox_Send () implementiert.
- Lesen einer Nachricht aus einer Mailbox. Nucleus SE implementiert die Funktion NUSE_Mailbox_Receive () .
- Wiederherstellen eines nicht verwendeten Postfachs mit der Freigabe aller angehaltenen Aufgaben (Zurücksetzen). In Nucleus SE, implementiert in NUSE_Mailbox_Reset () .
- Bereitstellung von Informationen zu einem bestimmten Postfach. Nucleus SE ist in NUSE_Mailbox_Information () implementiert.
- Gibt die Anzahl der aktuell in der Anwendung konfigurierten Postfächer zurück. In Nucleus SE, implementiert in NUSE_Mailbox_Count () .
- Hinzufügen eines neuen Postfachs (Erstellung). Nucleus SE ist nicht implementiert.
- Löschen Sie eine Mailbox. Nucleus SE ist nicht implementiert.
- Geben Sie Zeiger auf alle Postfächer in der Anwendung zurück. Nucleus SE ist nicht implementiert.
- Senden einer Nachricht an alle Aufgaben, die in der Mailbox angehalten sind (Broadcast). Nucleus SE ist nicht implementiert.
Betrachten Sie detailliert die Implementierung jedes Serviceabrufs.
Mailbox Read and Write Service Calls
Die grundlegenden Vorgänge, die für Postfächer ausgeführt werden können, sind das Schreiben und Lesen von Daten (Senden und Empfangen). Nucleus RTOS und Nucleus SE bieten zwei grundlegende API-Aufrufe für diese Operationen, die nachfolgend beschrieben werden.
In Mailbox schreiben
Das Aufrufen der Nucleus RTOS-API zum Schreiben in das Postfach ist sehr flexibel, sodass Sie die Aufgabe implizit oder mit einer Zeitüberschreitung anhalten können, wenn der Vorgang nicht sofort abgeschlossen werden kann (z. B. wenn Sie versuchen, in ein vollständiges Postfach zu schreiben). Nucleus SE bietet einen ähnlichen Serviceabruf, nur die Taskpause ist optional und das Timeout ist nicht implementiert.
Nucleus RTOS bietet auch einen Serviceabruf zum Senden von Daten an eine Mailbox an. Dieser Aufruf wird in Nucleus SE nicht unterstützt und wird im nächsten Artikel im Abschnitt „Nicht realisierte API-Aufrufe“ beschrieben.
Rufen Sie an, um in Nucleus RTOS in eine Mailbox zu schreibenPrototyp eines Serviceabrufs:
STATUS NU_Send_To_Mailbox (NU_MAILBOX * Mailbox, VOID * Nachricht, UNSIGNED Suspend);Parameter:
Mailbox - Zeiger auf die Mailbox;
Nachricht - ein Zeiger auf die zu sendende Nachricht, bestehend aus vier Elementen vom Typ
ohne Vorzeichen ;
suspend - Die Angabe der Suspendierung der Aufgabe kann die Werte
NU_NO_SUSPEND ,
NU_SUSPEND oder Timeout-Wert
annehmen .
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_MAILBOX - ungültiger Postfachzeiger;
NU_INVALID_POINTER - Nullzeiger auf eine Nachricht (
NULL );
NU_INVALID_SUSPEND - Versuch, einen nicht aufgabenbezogenen Thread auszusetzen;
NU_MAILBOX_FULL - Das Postfach ist voll, aber die Art der Aussetzung ist nicht angegeben.
NU_TIMEOUT - Das Postfach ist auch nach dem Aussetzen für den angegebenen Zeitraum noch voll.
NU_MAILBOX_DELETED - Das Postfach wurde gelöscht, während die Aufgabe angehalten wurde.
NU_MAILBOX_WAS_RESET - Das Postfach wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Rufen Sie an, um in eine Mailbox in Nucleus SE zu schreibenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Mailbox_Send (Postfach NUSE_MAILBOX, ADDR * -Nachricht, U8-Suspend);Parameter:
Postfach -
Postfachindex (ID);
message - ein Zeiger auf die zu sendende Nachricht, es ist eine Variable vom Typ
ADDR ;
suspend - Die Angabe der Suspendierung der Aufgabe kann die Werte
NUSE_NO_SUSPEND oder
NUSE_SUSPEND annehmen .
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_MAILBOX - ungültiger Postfachindex;
NUSE_INVALID_POINTER - Nullzeiger auf eine Nachricht (
NULL );
NUSE_INVALID_SUSPEND - ein Versuch, einen nicht verwandten Thread auszusetzen oder wenn die Funktion zum Blockieren von API-Aufrufen deaktiviert ist;
NUSE_MAILBOX_FULL - Das Postfach ist voll, aber die Art der Aussetzung ist nicht angegeben.
NUSE_MAILBOX_WAS_RESET - Das Postfach wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Implementieren von Postfacheinträgen in Nucleus SEDie Version des API-Funktionscodes
NUSE_Mailbox_Send () (nach Überprüfung der Parameter) wird mithilfe der bedingten Kompilierung ausgewählt, je nachdem, ob die Unterstützung für API-Aufrufe zum Blockieren (Anhalten von Aufgaben) aktiviert ist oder nicht. Betrachten Sie beide Optionen.
Wenn die Task-Sperre deaktiviert ist, ist die Logik für diesen API-Aufruf ziemlich einfach und der Code bedarf keiner Erklärung:
if (NUSE_Mailbox_Status[mailbox]) /* mailbox full */ { return_value = NUSE_MAILBOX_FULL; } else /* mailbox empty */ { NUSE_Mailbox_Data[mailbox] = *message; NUSE_Mailbox_Status[mailbox] = TRUE; return_value = NUSE_SUCCESS; }
Die Nachricht wird im entsprechenden Element
NUSE_Mailbox_Data [] gespeichert und das Postfach als verwendet markiert.
Wenn die Task-Sperre aktiviert ist, wird der Code komplexer:
do { if (!NUSE_Mailbox_Status[mailbox]) /* mailbox empty */ { NUSE_Mailbox_Data[mailbox] = *message; NUSE_Mailbox_Status[mailbox] = TRUE; if (NUSE_Mailbox_Blocking_Count[mailbox] != 0) { U8 index; /* check whether a task is blocked */ /* on this mailbox */ NUSE_Mailbox_Blocking_Count[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_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* mailbox full */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_MAILBOX_FULL; } else { /* block task */ NUSE_Mailbox_Blocking_Count[mailbox]++; NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Einige Erklärungen können hilfreich sein.
Der Code ist in einer
do ... while-Schleife eingeschlossen , die ausgeführt wird, während der
suspend- Parameter
NUSE_SUSPEND lautet .
Wenn das Postfach leer ist, wird die Nachricht aufgezeichnet und der Status des Postfachs ändert sich, um anzuzeigen, dass es voll ist. Überprüft dieses Postfach auf angehaltene Aufgaben (die darauf warten, gelesen zu werden). Wenn es solche Aufgaben gibt, wird die erste von ihnen fortgesetzt. Die Suspend-Variable wird auf
NUSE_NO_SUSPEND gesetzt , und der API-Aufruf wird beendet und gibt
NUSE_SUCCESS zurück .
Wenn das Postfach voll ist und suspend
NUSE_NO_SUSPEND ist , gibt der API-Aufruf
NUSE_MAILBOX_FULL zurück . Wenn suspend
NUSE_SUSPEND ist , wird die Aufgabe
angehalten . Wenn die Funktion nach Beendigung der Funktion (z. B. wenn die Aufgabe
fortgesetzt wird)
NUSE_SUCCESS lautet (was darauf hinweist, dass die Aufgabe fortgesetzt wurde, weil die Nachricht gelesen wurde und nicht, dass das Postfach zurückgesetzt wurde), beginnt der Zyklus von
vorne .
Mailbox lesen
Der Nucleus RTOS API-Dienstprogrammaufruf zum Lesen eines Postfachs ist sehr flexibel und ermöglicht es Ihnen, Aufgaben implizit oder mit einer Zeitüberschreitung anzuhalten, wenn der Vorgang nicht sofort abgeschlossen werden kann (z. B. beim Lesen aus einem leeren Postfach). Nucleus SE bietet einen ähnlichen Service, nur die Unterbrechung von Aufgaben ist optional und eine Zeitüberschreitung ist nicht implementiert.
Rufen Sie an, um eine Mailbox in Nucleus RTOS zu lesenPrototyp eines Serviceabrufs:
STATUS NU_Receive_From_Mailbox (NU_MAILBOX * Mailbox, VOID * Nachricht, UNSIGNED Suspend);Parameter:
Postfach - ein Zeiger auf die vom Benutzer bereitgestellte Postfachsteuereinheit;
Nachricht - ein Zeiger auf den Speicher für die empfangene Nachricht, dessen Größe vier Variablen vom Typ
ohne Vorzeichen entspricht ;
suspend - Task-Suspendierungsspezifikation, kann die Werte
NUSE_NO_SUSPEND ,
NUSE_SUSPEND oder Timeout-Wert
annehmen .
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_MAILBOX - ungültiger Postfachzeiger;
NU_INVALID_POINTER - Nullzeiger auf eine Nachricht (
NULL );
NU_INVALID_SUSPEND - Versuch, an einem falschen Stream
anzuhalten (nicht mit der Aufgabe des Streams verknüpft);
NU_MAILBOX_EMPTY - Das Postfach ist leer und die Art der Aussetzung wurde nicht angegeben.
NU_TIMEOUT - Das Postfach ist auch nach dem
Anhalten der Aufgabe für den angegebenen Zeitlimitwert noch leer.
NU_MAILBOX_DELETED - Das Postfach wurde gelöscht, während die Aufgabe angehalten wurde.
NU_MAILBOX_WAS_RESET - Das Postfach wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Rufen Sie an, um eine Mailbox in Nucleus SE zu lesenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Mailbox_Receive (Postfach NUSE_MAILBOX, ADDR * -Nachricht, U8-Suspend);Parameter:
Postfach -
Postfachindex (ID);
Nachricht - Ein Zeiger auf die Speicherung der empfangenen Nachricht ist eine Variable vom Typ
ADDR .
suspend - Die Angabe der Suspendierung der Aufgabe kann die Werte
NUSE_NO_SUSPEND oder
NUSE_SUSPEND annehmen .
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_MAILBOX - ungültiger Postfachindex;
NUSE_INDALID_POINTER - Nullzeiger auf eine Nachricht (
NULL );
NUSE_INVALID_SUSPEND - ein Versuch, einen falschen Stream auszusetzen oder wenn API-Aufrufe deaktiviert sind, um Aufgaben zu blockieren;
NUSE_MAILBOX_EMPTY - Das Postfach ist leer und die Art der
Taskunterbrechung ist nicht angegeben.
NUSE_MAILBOX_WAS_RESET - Das Postfach wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Implementieren des Mailbox Readers in Nucleus SEDie Version des API-Funktionscodes
NUSE_Mailbox_Receive () (nach Überprüfung der Parameter) wird mithilfe der bedingten Kompilierung ausgewählt, je nachdem, ob die API-Aufrufe zum Blockieren (Anhalten von Aufgaben) aktiviert sind oder nicht. Wir werden beide Optionen prüfen.
Wenn die Task-Sperre deaktiviert ist, ist die Logik für diesen API-Aufruf ziemlich einfach und der Code bedarf keiner Erklärung:
if (!NUSE_Mailbox_Status[mailbox]) /* mailbox empty */ { return_value = NUSE_MAILBOX_EMPTY; } else { /* mailbox full */ *message = NUSE_Mailbox_Data[mailbox]; NUSE_Mailbox_Status[mailbox] = FALSE; return_value = NUSE_SUCCESS; }
Die Nachricht wird aus dem entsprechenden Element
NUSE_Mailbox_Data [] gelesen und das Postfach als leer markiert.
Wenn die Task-Sperre aktiviert ist, wird der Code komplexer:
do { if (NUSE_Mailbox_Status[mailbox]) /* mailbox full */ { *message = NUSE_Mailbox_Data[mailbox]; NUSE_Mailbox_Status[mailbox] = FALSE; if (NUSE_Mailbox_Blocking_Count[mailbox] != 0) { U8 index; /* check whether a task is blocked */ /* on this mailbox */ NUSE_Mailbox_Blocking_Count[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_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* mailbox empty */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_MAILBOX_EMPTY; } else { /* block task */ NUSE_Mailbox_Blocking_Count[mailbox]++; NUSE_Suspend_Task(NUSE_Task_Active, (mailbox << 4) | NUSE_MAILBOX_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Einige Erläuterungen können hilfreich sein.
Der Code ist in einer
do ... while-Schleife eingeschlossen , die ausgeführt wird, während der
suspend- Parameter
NUSE_SUSPEND lautet .
Wenn das Postfach voll ist, wird die gespeicherte Nachricht zurückgegeben und der Status des Postfachs ändert sich, um anzuzeigen, dass es leer ist. Überprüft dieses Postfach auf angehaltene Aufgaben (die auf die Aufzeichnung warten). Wenn es solche Aufgaben gibt, wird die erste von ihnen fortgesetzt. Die Suspend-Variable wird auf
NUSE_NO_SUSPEND gesetzt , und der API-Aufruf wird beendet und gibt
NUSE_SUCCESS zurück .
Wenn das Postfach leer ist und der
Suspend- Parameter
NUSE_NO_SUSPEND lautet , gibt der API-Aufruf
NUSE_MAILBOX_EMPTY zurück . Wenn suspend
NUSE_SUSPEND ist , wird die Aufgabe
angehalten . Wenn am Ende des Aufrufs der Rückgabewert
NUSE_SUCCESS lautet , was darauf hinweist, dass die Aufgabe fortgesetzt wurde, weil die Nachricht gesendet wurde (und nicht, dass das Postfach zurückgesetzt wurde), beginnt der Zyklus von
vorne .
Im folgenden Artikel werden zusätzliche API-Aufrufe für Postfächer sowie die entsprechenden Datenstrukturen untersucht.
Ü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.