Embedded Software Manager Pattern

Embedded Software Manager Pattern – Teil 2: Die Manager und ihre Funktionalitäten

Jede Embedded-Software muss in der Praxis eine Vielzahl von verteilten und zentral koordinierten Aufgaben ausführen. Software Patterns stellen dabei nicht nur die konzeptionelle Integrität sicher, sondern ermöglichen auch die Skalierbarkeit über verschiedene Projekte hinweg. Im zweiten Teil unserer Beitragsreihe rücken wir die Manager mit ihren vielfältigen Funktionen in den Fokus.

Initialisierung (prozeduraler Ansatz)

Im prozeduralen Umfeld kommen Managermodule zum Einsatz, symbolisiert durch das „m“ vor den Namen. Im Architekturelement AEn ist der mAEnManager für seine Module m1…mN verantwortlich.

main() ruft init() vom mSoftwareManager auf. Diese Funktion ruft wiederum von allen mAEnManagern die initAEn() Funktionen in der erforderlichen Reihenfolge auf (Delegationen). Diese Funktionen initialisieren die Module aus deren Verantwortlichkeit. Das Prinzip der Delegation ist für die meisten weiteren Managerfunktionen anwendbar.

Bild 5: Manager Pattern für prozeduralen Ansatz

Im Vergleich zu einem objektorientierten Ansatz ist beim prozeduralen häufig keine Objektinstanziierung erforderlich. Somit könnten ggf. die create()Funktionen entfallen. Die aus der objektorientierten Programmierung bekannten Konstruktoren und Destruktoren von Klassen lassen sich in der prozeduralen Programmierung durch manuell aufzurufende Funktionen construct() und destruct() ersetzen.

Objektinstanziierung und Initialisierung (objektorientierter Ansatz)

main() instanziiert ein cSoftwareManager Ur-Objekt. Dieses instanziiert alle cAEnManager Objekte, die wiederum alle Objekte der Klassen c1…cN aus deren Verantwortung instanziieren. Abhängig von den angewandten Relationen (Assoziation, Aggregation) erzeugen die createX() Funktionen deren Objekte dynamisch und implementierungsabhängig auf dem Heap. Bei der durchgängig angewandten Komposition werden alle Objekte automatisch auf dem Stack angelegt, wobei die createX() Funktionen entfallen.

Die initX() Funktion erlaubt zusätzlich zum Konstruktor-Aufruf weitere Initialisierungen. Als Alternative ruft der Konstruktor die jeweilige initX() Funktion auf.

Bild 6: Manager Pattern für objektorientierten Ansatz

Ist die Architekturhierarchie tiefer als die hier dargestellte, erstreckt sich der oben beschriebene Ablauf über die gesamte Hierarchie.

Als Ergebnis dieses Schrittes sind alle Objekte instanziiert und grundinitialisiert.

Initialisierung der Relationen

Die Funktion buildXRelations() initialisiert die Relationen (Assoziation, Aggregation) zwischen den Objekten intern, aber auch über Architekturelement-Grenzen hinweg. Dazu gehören auch die Callback-Registrierungen. Typischerweise sind Zeiger mit entsprechender Objektaderesse initialisiert.

Bild 7: Manager Pattern um Relationsinitialisierung ergänzt

Häufig sind dazu Objektadressen aus nebenliegenden Architekturelementen erforderlich. Kennen sich diese AEnManager untereinander, so können sie Objektadressen übermitteln.

Konfiguration, Parametrierung, Datenbankzugriff

Nach der komplett abgeschlossenen Initialisierung detektiert die Software z.B., auf welcher Hardware die Ausführung stattfindet. Ergebnisabhängig liest der SoftwareManager die korrespondierenden Parameter aus einer lokalen oder in der Cloud befindlichen Datenbank.

Bild 8: Manager Pattern um Konfiguration ergänzt

Die Funktion configX() der AEnManager gibt die Parameter zu den zu konfigurierenden Klassen/ Modulen weiter. Eventuell ist configX() bereits vor initX() ausführbar und gibt die Parameter über die initX() Funktion weiter.

Allokation von Ressourcen

Die einzelnen Architekturelemente benötigen ggf. für den weiteren Betrieb zusätzliche individuelle Ressourcen. Besonders in einer funktional-sicherheitskritischen Embedded-Software ist es empfehlenswert, die erforderlichen Ressourcen bereits zu Beginn der Softwareausführung komplett anzulegen. Damit ist zum einen sichergestellt, dass alle Ressourcen zur Laufzeit verfügbar sind, zum anderen erfolgt dadurch gleichzeitig eine Laufzeit-Performanceverbesserung.

Bild 9: Manager Pattern um Ressourcen-Allokation ergänzt

Ressourcen sind z.B. Speicher oder bei Anwendung eines Betriebssystems bereits Betriebsmittel wie Mailboxen, Eventgruppen, Semaphore, Mutexe und Timer. Bedingung wäre, dass das Betriebssystem vor dem Bootvorgang dies bereits erlaubt. Falls nein, lässt sich die Reihenfolge der Funktionsaufrufe ändern oder der Funktionsaufruf allocateXResources() in die Architekturelement-spezifischen taskInit() verschieben.

Betriebsphase: Ohne Betriebssystem

Ein Bare-Metal-Applikation führt eine oder mehrere Funktionen kontinuierlich aus. Hier enthält die run() Funktion diese zentrale while(true) loop und führt in vorgegebener Reihenfolge kontinuierlich die runAEn() Funktionen aus.

Bild 10: Manager Pattern um Betriebsphase ergänzt

Boot-, Startup- und Betriebsphase: Mit Betriebssystem

Die start() Funktion des SoftwareMangers bootet das Betriebssystem. Anschließend schedult das Betriebssystem als erste Task die taskInit(). Diese kreiert taskOperation()und alle taskAEnInit()Tasks der AEnManager. Anschließend beendet sie sich selbst. Die taskAEnInit() kreiert taskARnOperation() und ggf. weitere Architekturelement-spezifische Tasks. Anschließend beendet sie sich ebenfalls. Nun beginnt die eigentliche Betriebsphase mit dem Scheduling der verbleibenden Tasks.

Bild 11: Manager Pattern für Startup und Betriebsphase

Die Manager-Taskfunktionen taskXOperation() enthalten einen Zustandsfolgeautomaten, der den aktuellen Zustand der Software bzw. der einzelnen Architekturelemente repräsentiert. Dieser Zustandsautomat ist im weiteren Verlauf des Kapitels vorgestellt.

Diagnose

Die Funktion executeDiagnostics() des SoftwareManagers startet die Diagnoseausführung und sammelt alle Diagnosedaten über die Aufrufe der in den AEnManagern enthaltenen executeAEnDiagnostics() Funktionen.

Bild 12: Manager Pattern um Diagnose ergänzt

Das Element Diagnostics speichert bzw. ermöglicht die Ausgabe der gespeicherten Daten.

Neustart

Die Funktion restart() des SoftwareManagers löst den Software-Neustart aus, indem die Aufrufe der in den AEnManagern enthaltenen restartAEn() Funktionen die einzelnen Architekturelemente neu aufstarten.

Bild 13: Manager Pattern um Neustart ergänzt

Zur feineren Unterteilung des Neustarts, aber auch des nachfolgend erklärten Herunterfahrens, dienen die gegenläufigen Funktionen zu denen, die die Manager während des Hochlaufs ausführen.

Herunterfahren

Die Funktion shutdown() des SoftwareManagers löst das Herunterfahren der Software aus, indem die Aufrufe der in den AEnManagern enthaltenen shutdownAEn() Funktionen die einzelnen Architekturelemente herunterfahren.

Bild 14: Manager Pattern um Herunterfahren ergänzt

Zentrale Fehlerbehandlung

Die Klassen c1…cN bzw. Module m1…mN erkennen ihre Fehler und melden diese ihrem AEnManager. Dieser leitet die Fehler direkt an den übergeordneten SoftwareManager weiter. Der SoftwareManager übernimmt zentral die Fehlerbehandlung, auch für potentiell auftretende Fehler in den AEnManagern.

Bild 15: Manager Pattern um zentrale Fehlerbehandlung ergänzt

Neben der richtigen Fehlerreaktion, z.B. mittels handleError() und recoverError(), übernimmt der SoftwareManager auch den Fehlereintrag in sein ErrorLogbook.

Dezentrale Fehlerbehandlung

Die Klassen c1…cN bzw. Module m1…mN erkennen ihre Fehler und melden diese ihrem AEnManager. Kann der AEnManager den Fehler bearbeiten, tut er dies und trägt den Fehler in sein lokales ErrorLogbook ein.

Bild 16: Manager Pattern um dezentrale Fehlerbehandlung ergänzt

Fatale Fehler, die der AEnManager nicht selbst bearbeiten kann, leitet er an den übergeordneten SoftwareManager weiter. Dieser übernimmt die Fatal-Fehlerbehandlung und trägt diese in sein ErrorLogbook ein.

Manager Zustandsfolge-Automat

Der SoftwareManager Zustandsfolge-Automat repräsentiert die möglichen Zustände der gesamten Software bzw. des Systems. Der AEnManager Zustandsfolge-Automat repräsentiert die möglichen Zustände des einzelnen Architekturelements.

Bild 17: Manager Zustandsfolge-Automat

Manager Ausführungsfluss

Bild 18: Manager Ausführungsfluss auf oberster Ebene

Als Zwischenzusammenfassung ist hier der Ausführungsablauf der einzelnen Funktionen auf Ebene des SoftwareManagers dargestellt. Dahinter verbergen sich die delegierenden Aufrufe der AEnManager. Dies ist nur eine Ablaufvariante von vielen möglichen.

Diskussionspunkte und Verbesserungen

Das bisher vorgestellte Manager Pattern lässt sich durch weitere Design- und Implementierungsdetails, aber auch Varianten verändern und ergänzen. Im Folgenden werden hierzu ein detaillierteres Grundkonzept und ein detaillierteres erweitertes Konzept vorgestellt.

Detailliertes Grundkonzept mit Fehlernotifikation

Im Common::Management sind das Fehler-Notifikationsinterface icbcErrorHandler (icbc == Interface Callback Class) und weitere Klassen für Diagnose und Fehlerbehandlung enthalten. Diese Elemente werden gleichermaßen in allen Managern verwendet.

Bild 19: Detailliertes Grundkonzept mit Fehlernotifikation

Das Applikationselement cN notifiziert über die notifyError() Funktion des Interfaces icbcErrorHandler die Fehler an den cAEnManager. Der cAEnManager wiederum notifiziert seine Fehler über das gleiche Interface an den cSoftwareManager.

Bei Anwendung der Komposition erfolgt die Objektinstanziierung als eingebettete Elemente/ Attribute:

Die Aufrufe der delegierten Funktionen müssen hier einzeln erfolgen, da keine gemeinsamen Typen definiert sind:

Der exemplarische C++ Programmcode des detaillierten Grundkonzepts ist im Download zu diesem Beitrag enthalten (siehe unten).

Detailliertes erweitertes Konzept mit Fehlernotifikation und Manager-Interface

Bild 20: Detailliertes erweitertes Konzept mit Fehlernotifikation und Manager-Interface

Bei Anwendung der Assoziation/ Aggregation erfolgt die Objektinstanziierung dynamisch und der Zugriff über Zeiger:

Die Aufrufe der delegierten Funktionen erfolgen in einer Schleife (einfach erweiterbar), da alle cAEnManager den gemeinsame Interfacetype icAEnManager (ic == Interface Class) implementieren und der cSoftwareManager über ein Zeigerarray darauf zugreift:

Der exemplarische C++ Programmcode des detaillierten erweiterten Konzepts ist im Download zu diesem Beitrag enthalten (siehe unten).

Resümee

In der Praxis muss jede Embedded-Software die hier vorgestellten verteilten und zentral zu koordinierenden Aufgaben ausführen. Anforderungsabhängig sind weniger oder mehr dieser Aufgabenart auszuführen. Um die konzeptionelle Integrität auch über mehrere Projekte zu wahren, eignet sich der Einsatz von Software Patterns. Wie bei jedem Pattern müssen der Softwarearchitekt, der Softwareentwickler bzw. das Softwareteam die hier exemplarisch vorgestellten Strukturen und Abläufe auf die individuellen Gegebenheiten in der Software anpassen.

Der 1. Teil des Beitrags beleuchtet die Grundlagen des Manager Pattern für die Koordination verschiedener zentraler Aufgaben der Software.

Holen Sie sich das richtige Wissen darüber, wie das Embedded Software Manager Pattern in Ihren Software-Architekturen und Ihrem Software-Design anzuwenden ist. Dabei lassen Sie das Konzept mit der immer steigenden Komplexität der Software, unabhängig von der Programmiersprache und dem Programmieransatz (prozedural / objektorientiert), dauerhaft mitwachsen. MicroConsult bietet Ihnen dazu professionelle Trainings und Coachings rund um die Themen Analyse, Design und Architektur uvm. an.

Weiterführende Informationen

Beitrag Teil 1

MicroConsult-Download für diesen Beitrag, komplett und aktuell (zip)

MicroConsult Fachwissen zum Thema Embedded SW-Entwicklung

MicroConsult-Trainings zum Thema:

Alle Trainings & Termine auf einen Blick

Veröffentlicht von

Thomas Batt

Thomas Batt

Thomas Batt studierte nach seiner Ausbildung zum Radio- und Fernsehtechniker Nachrichtentechnik. Seit 1994 arbeitet er kontinuierlich in verschiedenen Branchen und Rollen im Bereich Embedded-/Realtime-Systementwicklung. 1999 wechselte Thomas Batt zur MicroConsult GmbH. Dort verantwortet er heute als zertifizierter Trainer und Coach die Themenbereiche Systems/ Software Engineering für Embedded-/Realtime-Systeme sowie Entwicklungsprozess-Beratung.