• Keine Ergebnisse gefunden

3 GERÄTEMANAGEMENT

3.3 Konzept eines neuartigen Gerätemanagement-Systems

3.3.2 Highlevel-Interface

Dieses Namespace-Objekt können alle Softwarekomponenten nutzen, um eigene Slots oder Subnamespaces hinzuzufügen.

dennoch vor. Zu dieser Gruppe von Nodes gehören z.B. der Network-Node, der dafür verantwortlich ist, die Netzwerktransparenz herzustellen (siehe Kapitel 4), der Node, der es erlaubt, das Gerätemanagement-System über einen normalen Web-Browser zu konfigurieren (siehe Kapitel 6), oder der Inline-Node, der es erlaubt, Datenflußgraphen aus Dateien nachzuladen und in den aktuellen Datenflußgraphen zu integrieren.

Nodes sind von Namespaces abgeleitet. Das bedeutet, daß sie genauso wie Namespaces verwendet werden können, d.h. man kann sie in die Namespace-Hierarchie einbauen sowie Outslots, Inslots und Routes hinzufügen. Allerdings macht es normalerweise wenig Sinn, Slots und Routes einem Node hinzuzufügen. Nodes sind Softwaremodule, die Outslots und Inslots in übergeordnete Namespaces exportieren und über diese Slots Daten an die Anwendung oder andere Nodes senden, oder Daten von der Anwendung oder anderen Nodes empfangen. Das Ziel ist es dabei, der Anwendung einen Pool von kleinen Modulen bereitzustellen, die klar umrissene Aufgaben haben. Die Anwendung kann diese Module zu einem Graphen zusammenstellen, der Daten von Geräten empfängt und in ein für die Anwendung brauchbares Format transformiert, oder Daten von der Anwendung in ein für die Geräte brauchbares Format transformiert und an die Geräte überträgt. Dabei können Teilbäume des Graphen auf verschiedenen Rechnern im Netzwerk laufen.

Eine wichtige Entscheidung, die der Entwickler eins Knotens fällen muß, ist die Frage, ob ein Knoten einen eigenen Thread erhalten sollte oder nicht. Knoten, die Datenwerte von Eingabegeräten lesen und dem System zur Verfügung stellen, erhalten normalerweise einen eigenen Thread, da sie an der Schnittstelle, an die das Gerät angeschlossen ist, auf neue Datenwerte warten müssen. Diese Möglichkeit, jeden Knoten mit einem eigenen Thread zu versehen, stellt einen großen Unterschied zu vielen existierenden Gerätemanagement-Systemen dar. Das hier beschriebene System ist kein Single-Thread-System, wo regelmäßig von einer Anwendung eine Methode aufgerufen werden muß, um aktuelle Datenwerte zu erhalten (das sogenannte „Polling“). Anstelle dessen kann jeder Knoten selbst aktiv sein und die Anwendung über Events (also über das Versenden von neuen Datenwerten über Outslots) auf Veränderungen hinweisen. Dies ist insbesondere auf leistungsschwachen mobilen Systemen wichtig, wo man die knappe Ressource Rechenzeit nicht durch unnützes Polling verschwenden will. Damit beim Einsatz mehrerer Threads die Datenkonsistenz gewahrt bleibt, ist die Datenübertragung über Outslots und Inslots thread-safe angelegt, d.h. Slots sind über Mutexe gegen den gleichzeitigen Zugriff zweier Threads geschützt.

Andere Knoten wie z.B. Filterknoten müssen keinen eigenen Thread enthalten. Diese Knoten können sich über Callbacks darüber informieren lassen, daß ein neuer Datenwert zur Verarbeitung eingetroffen ist, d.h. es wird immer dann, wenn ein Datenwert in einen InSlot des Knoten geschrieben wird, eine Methode des Knotens aufgerufen. Die Verarbeitung der Daten im Knoten wird dabei de facto von dem Thread übernommen, der den neuen Datenwert produziert hat, also üblicherweise dem Thread eines Gerätetreiber-Knotens. Allerdings können Filterknoten auch einen eigenen Thread enthalten. Dies empfiehlt sich immer dann, wenn die Verarbeitung der gelieferten Daten sehr zeitaufwendig ist, wie z.B. bei einem Videotracking-Knoten. Ohne einen eigenen Thread wäre der Thread des Videograbber-Knotens, der die digitalisierten Videobilder liefert, bis zum Ende des Tracking-Prozesses blockiert. Dadurch, daß der Tracking-Knoten einen eigenen Thread erhält, kann der Videograbber-Knoten dagegen schon während der Verarbeitung ein neues Bild von der Kamera entgegennehmen, d.h. die Parallelität der Verarbeitung steigt.

Nodes können von der Anwendung direkt erzeugt werden, da sie normale C++- bzw. Java-Objekte sind. Dann können Methoden dieser Java-Objekte aufgerufen werden, um verschiedene Parameter zu setzten. Danach werden die Nodes in die Namespace-Hierarchie eingefügt und

ihre Slots über Routes mit den Slots anderer Nodes oder den Slots der Anwendung verbunden.

Allerdings ist dieser Weg unflexibel, weil die Anwendung zum Erzeugen der Node-Instanzen die Node-Klasse zur Compile-Zeit kennen muß. Genau daß ist jedoch nicht erwünscht – schließlich soll die Anwendung ja zur Laufzeit umkonfiguriert werden und über Plugin-Mechanismen mit neuen Geräte-Treibern ausgerüstet werden können. Es muß also ein Weg gefunden werden, Nodes zu erzeugen, ohne die konkrete Nodeklasse zu kennen. Dies geschieht über einen System von Typ-Objekten, die Meta-Informationen über die verschiedenen Node-Klassen besitzen, sowie eines Factory-Objekts – ein klassisches Design Pattern, das z.B. schon vom 3D-Toolkit Inventor [65] verwendet wurde.

Zu jeder Node-Klasse gibt es ein Typ-Objekt, das eine Reihe von Meta-Informationen speichert:

• Einen eindeutigen Identifier. Dieser Identifier ist ein beliebiger Text-String, der verwendet wird, um die Node-Klasse aus der Anwendung heraus anzusprechen.

• Die Adresse einer Funktion, die neue Instanzen der jeweiligen Nodeklasse erzeugen kann.

• Informationen über die Parameter, die ein Node benötigt. Diese Information besteht aus den Parameter-Namen, den Parameter-Datentypen, und den Default-Werten, der verwendet werden, wenn die Anwendung den jeweiligen Parameter nicht spezifziert.

Darüber hinaus werden die Klassenmethoden zum Lesen und Schreiben der jeweiligen Parameter gespeichert.

• Diversen anderen Informationen, die zwar vom Gerätemanagement-System nicht verwendet werden, aber Dokumentationszwecken dienen, wie z.B. Informationen über den Einsatzzweck eines Node, über die Personen, die den Node programmiert haben, sowie Beschreibungen der verfügbaren Parameter.

Die Typ-Objekte werden als statische Objekte angelegt, d.h. sie werden automatisch beim Programmstart oder beim Laden eines Plugins instanziiert und tragen sich automatisch in eine Liste aller verfügbaren Typ-Objekte ein.

Anwendungen können jetzt mittels eines Node-Factory-Objekts Instanzen von Nodes erzeugen, indem sie den Node-Identifier verwenden. Das Factory-Object sucht in der Liste der Typ-Objekte das Typ-Objekt mit diesem Identifier, und verwendet die im Typ-Objekt vorhandene Methode, um eine Instanz des gewünschten Nodes zu erzeugen. Dieses Node-Objekt wird dann von der Factory an die Anwendung zurückgeliefert.

Auch Parameter können von der Anwendung gelesen oder geschrieben werden, ohne daß die Anwendung das Interface der Klasse kennen muß. Dazu gibt es in der abstrakten Node-Klasse, die der Vorfahre aller konkreten Node-Klassen ist, Methoden zum Lesen und Schreiben von Parametern. Die Methode zum Lesen von Parametern bekommt von der Anwendung einen String mit dem Namen des Parameters. Die Node-Klasse verwendet das zugehörige Typ-Objekt, um die zum Auslesen des Parameters benötigte Methode zu bestimmen und aufzurufen. Der von der Methode zurückgelieferte Parameter-Wert wird automatisch in einen String umgewandelt und an die Anwendung zurückgeliefert. Die Methode zum Schreiben von Parametern funktioniert analog – sie erhält von der Anwendung ebenfalls den Namen des Parameters und einen String mit dem Parameterwert. Die Node-Klasse verwendet das zugehörige Typ-Objekt, um die zum Schreiben des Parameters benötigte Methode zu bestimmen. Sie wandelt den Parameter-String automatisch in den benötigten Parameter-Datentyp um und ruft die Methode auf, um den Parameter zu setzen.

Das in diesem Abschnitt beschriebene System von Meta-Typinformationen und dem Node-Factory-Objekt eignet sich bereits dazu, die von der Anwendung verwendete Gerätekonfiguration über ein User-Interface während der Laufzeit zu modifizieren oder in Konfigurationsdateien zwischenzuspeichern. Weil das Speichern einer Gerätekonfiguration in einer Datei und das Wiederherstellen einer Gerätekonfiguration aus einer Datei ein häufig verwendete Vorgehensweise ist, um Anwendungen unabhängig von der im jeweiligen Fall verwendeten Gerätehardware zu machen, wird im folgenden Kapitel ein Standard-Format für eine solche Konfigurationsdatei beschrieben.