Hochschule Darmstadt Entwurf und

Transcrição

Hochschule Darmstadt Entwurf und
Hochschule Darmstadt
­ Fachbereich Informatik ­
Entwurf und Implementierung
eines Multi­HMI Konzeptes
Zur Anbindung von Mobile/Remote­HMIs an ein InCarMultimedia­System
Abschlussarbeit zur Erlangung des akademischen Grades
Master of Science (M.Sc.)
vorgelegt von
Stefan Jäger
Referent:
Prof. Dr. Joachim Wietzke
Korreferent:
Prof. Dr. Ralf Hahn
Erklärung
Ich versichere hiermit, dass ich die vorliegende Arbeit selbstständig verfasst und keine anderen als die im Literaturverzeichnis angegebenen Quellen benutzt habe. Alle Stellen, die wörtlich oder sinngemäß aus veröffentlichten oder noch nicht veröffentlichten Quellen entnommen sind, sind als solche kenntlich gemacht. Die Zeichnungen oder Abbildungen in dieser Arbeit sind von mir selbst erstellt worden oder mit einem entsprechenden Quellennachweis versehen.
Diese Arbeit ist in gleicher oder ähnlicher Form noch bei keiner anderen Prüfungsbehörde eingereicht worden.
Darmstadt, den 06.10.2006
2
Abstrakt
Moderne Multimedia­Systeme für das Auto werden immer leistungsfähiger und sind dadurch in die Lage versetzt, mehrere Funktionen gleichzeitig ausüben zu können. Interessant sind vor allem die Möglichkeiten, die Unterhaltungsfunktionen gleichzeitig weiteren Mitfahrern im Auto verfügbar zu machen, das sogenannte Rear­Seat­Entertainment.
Im Rahmen dieser Arbeit wurden diese Fähigkeiten in das an der Hochschule entwickelte Multimedia­Framework eingebunden. Es wurden Konzepte für die verschiedenen Problemstellungen entwickelt. Neben der Kommunikation zwischen der Remote­HMI und dem Multimedia­System zeigt sich die Notwendigkeit eines durchdachten Konzeptes zur prioritätsgesteuerten Rechte­ und Ressourcenvergabe. Durch die Realisierung einer dazu bestimmten Software­Komponente wurde es möglich, das System mit mehreren Bedieneinheiten in Kombination mit verschiedenen Verstärkern und Abspielgeräten zu betreiben.
Für den Testbetrieb wurde eine Remote­HMI mit minimaler Funktionalität entwickelt, die über WLAN an das Hauptsystem angebunden ist. Die für einen mit Linux betriebenen PDA entworfene Anwendung integriert vollständig die betrachteten Konzepte und ist so als Referenz­Implementierung für weiterführende Remote­Anwendungen brauchbar.
3
Abstract
Modern sophisticated multimedia systems for InCar application with their increasing computing power are able to take care of many tasks at the same time. The useful and announced possibility to use the Entertainment­Features concurrently with other passengers, named as Rear­Seat­Entertainment is the main­subject of this thesis.
The needed features have been integrated into the given multimedia­framework and also the concepts related to the different problems are shown and described in this work. In addition to this, one of the tasks was to think of the appropriate communicational mechanism. Furthermore this work shows the need for an elaborated concept to manage a priority based allocation of rights and resources. The realisation of a dedicated software component dealing with this task, made it possible to run the system with multiple HMI­units in combination with a various number of amplifiers and play back devices. For testing purposes and as a result of this work a remote HMI with a subset of possible functionality was developed, which was connected to the main unit via a WLAN connection. This application runs on a Linux­PDA, integrates the described concepts completely and could be used as a reference implementation for future development of remote applications.
4
Vorwort
Auf die Übersetzung verschiedener englischer Fachbegriffe wurde in den meisten Fällen verzichtet, da die Verwendung englischer Bezeichnungen eine übliche Verfahrensweise in der Informatik ist.
Aus technischen Gründen unterliegen Variablennamen bei Programmiersprachen gewissen Einschränkungen. Beispielsweise ist der Bindestrich der mathematischen Substraktionsberechnung vorbehalten und darf deshalb nicht im Namen enthalten sein. Die Zusammen­ und Getrenntschreibung von Objekt­, Komponenten­ oder Variablennamen ist an der Schreibweise im Quelltext und nicht an der deutschen Rechtschreibung orientiert.
5
Inhaltsverzeichnis
Erklärung..................................................................................................................................2
Abstrakt.....................................................................................................................................3
Abstract.....................................................................................................................................4
Vorwort.....................................................................................................................................5
Abkürzungsverzeichnis...........................................................................................................10
1 Einleitung............................................................................................................................16
2 Grundlagen .........................................................................................................................17
2.1 Begriffserklärungen.....................................................................................................17
2.1.1 Target....................................................................................................................17
2.1.2 Framework............................................................................................................17
2.1.3 Komponente.........................................................................................................18
2.1.4 MainDispatcher....................................................................................................18
2.1.5 HMI (Human­Mashine­Interface)........................................................................18
2.2 MOST..........................................................................................................................19
2.3 Verwendete Hardware.................................................................................................22
2.3.1 InCarMultimedia­Systeme...................................................................................22
2.3.1.1 Target PON...................................................................................................22
2.3.1.2 Target NG3...................................................................................................23
2.3.2 Remote Geräte.....................................................................................................24
2.3.2.1 HP­iPAQ h5500............................................................................................24
2.3.2.2 Siemens S65 Mobiltelefon...........................................................................24
3 Konzept...............................................................................................................................25
3.1 Framework im Ausgangszustand.................................................................................25
3.2 Das InCarMultimedia­System im Wandel...................................................................26
3.2.1 Die Unterbringung der Verwaltung in einer Remote­HMI..................................28
3.2.2 Die Unterbringung der Verwaltung in der lokalen HMI.....................................28
3.2.3 Die Unterbringung der Verwaltung in einer neuen Komponente........................29
3.2.4 Designentscheidungen der einzelnen Komponenten...........................................31
3.2.4.1 Amplifier .....................................................................................................31
3.2.4.2 Abspielgeräte...............................................................................................33
6
3.2.4.3 MOST­Treiber..............................................................................................34
3.2.4.4 Ist­ und Soll­Datencontainer........................................................................35
Szenario:..............................................................................................................36
3.2.5 Implementierung des AudioMasters....................................................................37
3.2.5.1 Übergangstabelle..........................................................................................37
3.2.5.2 Prioritätssystem............................................................................................37
3.2.5.3 Class vs. Struct.............................................................................................40
Speicherplatz........................................................................................................40
Geschwindigkeit...................................................................................................41
Daten­Kapselung..................................................................................................41
3.2.5.4 Umschaltlogik..............................................................................................42
3.2.6 Anbindung der Remote­HMI...............................................................................42
3.2.7 UpdateEvents und DatenContainer......................................................................43
3.3 Remote­HMI als MOST­Device..................................................................................45
3.4 AudioMaster................................................................................................................46
3.4.1 Szenario...............................................................................................................48
3.4.2 Prioritätsvergabe..................................................................................................51
4 Eine einheitliche Grafik für alle Geräte..............................................................................52
4.1 Display.........................................................................................................................52
4.2 Hardware / Software....................................................................................................53
4.3 Hard­ und Softkeys......................................................................................................55
5 Entwicklung einer HMI für den HP­iPAQ h5500...............................................................57
5.1 Betriebssysteme für PDAs...........................................................................................57
5.1.1 Distribution..........................................................................................................57
5.2 Grafik für Linux PDA's...............................................................................................58
5.2.1 QTE / Qt­Embedded............................................................................................58
5.2.2 Opie.....................................................................................................................59
5.2.3 OTopia / QPE .....................................................................................................59
5.2.4 GPE ....................................................................................................................60
5.2.5 GTK+ vs. Qt­Embedded......................................................................................60
5.3 Ein neues Betriebssystem auf den PDA spielen..........................................................61
5.4 Qt/Qt­Embedded..........................................................................................................61
7
5.4.1 Signal­Slot...........................................................................................................62
5.5 Designer......................................................................................................................64
5.6 UIC ­ User­Interface­Compiler...................................................................................65
5.7 MOC ­ Meta­Object­Compiler....................................................................................65
5.8 Qt­Assistant.................................................................................................................65
5.9 Remote HMI als High­Level­Komponente.................................................................66
5.9.1 Der DisableButton...............................................................................................68
5.9.1.1 Die MyPic­Klasse........................................................................................69
5.10 Das Hilfsprogramm Converter...................................................................................71
5.10.1 Vom Button­Click bis zur Anzeige....................................................................72
5.11 Qt Linguist.................................................................................................................74
5.12 TMAKE.....................................................................................................................78
5.13 QMAKE.....................................................................................................................78
5.14 MAKE........................................................................................................................78
5.15 Executeables für den HP­iPAQ erzeugen...................................................................81
5.15.1 Konsole und Umgebungsvariablen.....................................................................82
5.16 Unterscheidung Qt/X11 und Qt/E..............................................................................83
5.17 Eigene Widgets..........................................................................................................85
5.17.1 Bar......................................................................................................................85
5.18 KUI­Viewer................................................................................................................89
5.19 Remote­HMI in Qt.....................................................................................................91
5.20 Icon für den PDA­Desktop erstellen..........................................................................94
5.21 Auslieferung der Software an den PDA.....................................................................95
6 Entwicklung einer HMI für Mobiltelefone.........................................................................96
6.1 Betriebssysteme für Mobiltelefone..............................................................................96
6.2 Java..............................................................................................................................96
6.3 J2ME...........................................................................................................................97
6.3.1 Configurations.....................................................................................................97
6.3.2 Profiles................................................................................................................98
6.3.3 Optional packages ..............................................................................................98
6.3.4 KVM....................................................................................................................98
6.3.5 ByteCode­Verifikation.........................................................................................99
8
6.3.6 MIDlets entwickeln.............................................................................................99
6.4 WTK .........................................................................................................................100
6.5 Grafik........................................................................................................................102
7 Irrwege...............................................................................................................................110
8 Anhang..............................................................................................................................111
8.1 Crosstoolchain............................................................................................................111
8.1.1 arm­linux­readelf................................................................................................112
8.1.2 arm­linux­addr2line............................................................................................112
8.1.3 arm­linux­ar........................................................................................................112
8.1.4 arm­linux­ranlib.................................................................................................113
8.1.5 arm­linux­nm......................................................................................................113
8.1.6 arm­linux­size.....................................................................................................113
8.1.7 arm­linux­cpp.....................................................................................................113
8.1.8 arm­linux­strings................................................................................................113
8.1.9 arm­linux­gdb.....................................................................................................114
8.1.10 arm­linux­objcopy.............................................................................................114
8.1.11 arm­linux­gcov..................................................................................................114
8.1.12 arm­linux­as......................................................................................................115
8.1.13 arm­linux­objdump...........................................................................................115
8.1.14 arm­linux­strip..................................................................................................115
8.1.15 arm­linux­ld......................................................................................................115
8.1.16 arm­linux­c++filt..............................................................................................116
8.1.17 Crosscompiler ..................................................................................................117
9 Fazit...................................................................................................................................118
10 Zusammenfassung...........................................................................................................119
11 Ausblick...........................................................................................................................120
11.1 Handy.......................................................................................................................120
11.2 AudioMaster............................................................................................................120
11.3 Lokale HMI..............................................................................................................121
11.4 Software­Paket.........................................................................................................121
11.5 Plattformunabhängigkeit..........................................................................................121
12 Danksagung.....................................................................................................................122
9
Abkürzungsverzeichnis
API
Application Programming Interface
CDC
Connected Device Configuration
CLDC
Connected Limited Device Configuration
CPU
Central Processing Unit
ELF
Executable and Linking Format
FPU
Floating­Point­Unit
GPE
GPE Palmtop Environment
GUI
Graphical User Interface
HCI
Host Controller Interface
HMI
Human Mashine Interface
ICM
In­Car­Multimedia
J2ME
Java 2 Micro Edition
JAD
Java Application Descriptor
JAR
Java Archive
JVM
Java Virtual Mashine
KDE
K Desktop Environment
KVM
Kilobyte Virtual Mashine
L2CAP
Logical Link Control and Adaption Protocol
LCD
Liquid Crystal Display
MIDP
Mobile Information Device Profile
MMI
Mensch Maschine Interface
MOC
Meta Object Compiler
MOST
Media Oriented Systems Transport
OPIE
Open Palmtop Integrated Environment
PDA
Personal Digital Assistant
PIM
Personal Information Manager
POSIX
Portable Operating System Interface (Uni)X
RAM
Random Access Memory
RFCOMM
Radio Frequency Communication
SDP Service Discovery Protocol
10
SMTK
Siemens Mobility Toolkit
SSH
Secure Shell
TTY
Teletypes / Teletypewrite
UDP
User Datagram Protocol
UIC
User Interface Compiler
WINE
WINE Is Not an Emulator WTK
J2ME Wireless Toolkit (von Sun Microsystems, Inc.)
11
Abbildungsverzeichnis
Abbildung 1: MOST­Devices..................................................................................................20
Abbildung 2: InCarMultimedia­System (Target PON)...........................................................22
Abbildung 3: InCarMultimedia­System (Target NG3)............................................................23
Abbildung 4: HP­iPAQ h5500 (Pocket PC) aus [hp­2006].................................................24
Abbildung 5: S65 (aus [Drex­2006])......................................................................................24
Abbildung 6: AudioMaster zur Ressourcen Verwaltung.........................................................30
Abbildung 7: MostProxy Inheritance Graph...........................................................................32
Abbildung 8: Anbindung der Remote­HMI an das Framework..............................................42
Abbildung 9: LOST_CONTROL............................................................................................47
Abbildung 10: GOT_CONTROL............................................................................................47
Abbildung 11: Interaktion mit dem AudioMaster (Sequenzdiagramm)..................................50
Abbildung 12: Display­Sizes...................................................................................................52
Abbildung 13: QNX's Grafik Abstraktionen angelehnt an [qnx­2006]...................................54
Abbildung 14: MiniCom.........................................................................................................55
Abbildung 15: MainMenu.......................................................................................................55
Abbildung 16: TunerMenu......................................................................................................55
Abbildung 17: MiniCom­Simulator........................................................................................56
Abbildung 18: MaxiCom­Simulator.......................................................................................56
Abbildung 19: QTopia PDA Edition (aus [lugod­2006])......................................................59
Abbildung 20: GPE (aus [Hand­2006])..................................................................................60
Abbildung 21: Verbinden von Signalen mit Slots im Designer..............................................64
Abbildung 22: Signal­Slot Verbindungen...............................................................................64
Abbildung 23: Aufbau der CMessage.....................................................................................66
Abbildung 24: Forken bei Konsolen­Applikationen...............................................................82
Abbildung 25: Bar­Widget 40%..............................................................................................85
Abbildung 26: Bar­Widget 70%..............................................................................................86
Abbildung 27: Bar­Widget 40% mMiddleBar=false...............................................................86
Abbildung 28: verschiedene Qt Styles in KUI­Viewer............................................................90
Abbildung 29: ScreenShot Opie (Games­Tab) .......................................................................94
Abbildung 30: J2ME & J2SE im Vergleich (angelehnt an [Schm­2004])..............................97
12
Abbildung 31: Projekteinstellungen für J2ME Projekte........................................................100
Abbildung 32: Memory Monitor Graph................................................................................101
Abbildung 33: Memory Monitor Objects..............................................................................101
Abbildung 34: J2ME Simulation...........................................................................................103
Abbildung 35: High­Level Applikation auf Siemens S65.....................................................103
Abbildung 36: Bluetooth Dienste des Siemens­S65.............................................................106
Abbildung 37: Bluetooth Dienste des Target NG3................................................................106
13
Tabellenverzeichnis
Tabelle 1: FunctionBlockID der MOST­Devices....................................................................21
Tabelle 2: In der Entwicklung stehende HMIs........................................................................26
Tabelle 3: Connection Registry...............................................................................................38
Tabelle 4: Registry nicht normalisiert.....................................................................................39
Tabelle 5: HMI­Tabelle...........................................................................................................39
Tabelle 6: Destination­Tabelle.................................................................................................40
Tabelle 7: Source­Tabelle........................................................................................................40
Tabelle 8: Registry­Tabelle......................................................................................................40
14
Listingverzeichnis
Listing 1: Forken der Amplifier in der AdminComponent.cpp ..............................................33
Listing 2: Variablen zur Zuordnung von FunctionBlockID und InstanceID zu DeviceID .....35
Listing 3: Konsolenausgabe des Converters............................................................................71
Listing 4: Makefile..................................................................................................................79
Listing 5: buildscript.sh...........................................................................................................81
Listing 6: Ausschnitt aus InCarMultimedia main.cpp.............................................................84
Listing 7: Header­Datei Bar.h.................................................................................................87
Listing 8: Styleangaben für Qt­Programme............................................................................89
Listing 9: Datei Amplifier.h....................................................................................................92
Listing 10: Slot IncBass() Amplifier.cpp................................................................................93
Listing 11: “icm.desktop“­Datei..............................................................................................94
Listing 12: Script for fetching and installing file....................................................................95
Listing 13: Quellcode einer J2ME High­Level GUI Applikation.........................................104
Listing 14: Inhalt einer Jad­Datei..........................................................................................105
Listing 15: Einige Imports für Bluetooth unter J2ME...........................................................105
Listing 16: Bluetooth­Dienste des S65 ausgelesen mit sdptool.............................................107
15
1 Einleitung
Seit der Erfindung des Automobils versuchen die Hersteller, sich von ihrer Konkurrenz durch immer neuere und fortschrittlichere Automobile abzuheben, sei es auf dem Gebiet der Leistung, der Eleganz, der Sportlichkeit, des Raumangebotes, der Ausstattung oder der Sparsamkeit. Heutzutage gibt es für jede Zielgruppe perfekt konfigurierte Automobile, die den jeweiligen Ansprüchen der Zielgruppe größtenteils entsprechen. Damit die Hersteller ihre Marktposition festigen oder weiter ausbauen, finden seit einigen Jahren immer mehr elektronische Bauteile ihren Weg in das Automobil. Mit den früheren, vorwiegend mechanisch arbeitenden Automobilen haben die heutigen Versionen kaum noch Ähnlichkeit. Klimaautomatik, Sitzheizung, Abstandssensor und Rückfahrkamera gehören schon lange bei vielen Modellen zum Standard und faszinieren den Kunden kaum noch. Navigationssysteme erleichtern dem Fahrer die Fahrt zu unbekannten Zielen, Freisprechanlagen ermöglichen das Telefonieren und auch Unterhaltungselektronik wie das Internet und Audio­Visuelle­
Anlagen, halten ihren Einzug in das Automobil. In einem InCarMultimedia­System soll diese Technik vernetzt und perfekt in das Auto integriert sein. Einstellungen wie die Sitzposition, Ausrichtung der Spiegel, Innenraumtemperatur, Radiosender und weitere Merkmale sollen personenspezifisch gespeichert und für den Benutzer bequem und einfach über ein optisches Bediensystem veränderbar sein. Mit dieser Steuerung befasst sich diese Masterthesis. Es soll ein Konzept einwickelt werden, das es ermöglicht, mehrere HMI's (Human Mashine Interface) an einem InCarMultimedia­System zu betreiben, um später eine oder mehrere Remote­HMIs verwenden zu können. In unserem Fall soll die Remote­HMI es den Kindern auf den Rücksitzen ermöglichen ihren Kopfhörerausgang selbst zu steuern.
16
2 Grundlagen 2.1 Begriffserklärungen
2.1.1 Target
Der Begriff Target besitzt in dieser Abschlussarbeit zwei verschiedenen Bedeutungen, die gerade verwendete Bedeutung ist anhand des Kontextes erkennbar.
1. Im Embedded­Bereich entwickelt man die Software aus Bequemlichkeit meist am PC und überträgt die fertige Software dann auf das Ziel­System; dieses ist die Hardware, auf dem die fertige Software eingesetzt werden soll. Das Ziel­System wird auch kurz einfach nur Target (deutsch: Ziel) genannt.
2. Beim Tool Make kommt dieser Begriff ebenfalls vor. Hier stellt er nicht Hardware, sondern ein Stück Software dar. Das Tool Make veranlasst Programme dazu, aus Quelldateien, Objekt­Dateien zu erzeugen und aus Objekt­Dateien Binaries. Die Objekt­Dateien sind also Zwischen­Ziele und das Binary das End­Ziel. Im Englischen spricht man von Sub­Target und Target. 2.1.2 Framework
Ein Framework ist ein Rahmen, der die Anwendungsarchitektur vorgibt, dabei wird im Wesentlichen darauf geachtet, dass Projekte wiederverwendbar gehalten und Schnittstellen zur Kommunikation bereitgestellt werden, dies ermöglicht es auch in größeren Gruppen an einem Projekt zu arbeiten. Meist sind Frameworks domänenspezifisch, sie sind deshalb je nach Anwendungsgebiet sehr unterschiedlich. Ein gutes Framework ist schlank gehalten und ist deshalb auch für verschiedene Projekte einsetzbar. Auf was es bei einem InCarMultimedia­Framework im einzelnen ankommt, kann in [WiTr­2005] S.13 ff nachgelesen werden.
17
2.1.3 Komponente
Das verwendete InCarMultimedia­Framework besteht aus verschiedenen Komponenten. Diese Komponenten sind Software­Module, die unabhängig gestartet, überwacht, beendet und gegebenenfalls neu gestartet werden können. Die Admin­Komponente ist die Hauptkomponente unseres Frameworks. Sie ist ein Prozess, welcher geforkt wird und in dessen Kindprozessen alle anderen Komponenten ausgeführt werden. Einer dieser Prozesse ist der Watchdog Prozess. Er überwacht den Lebenszyklus aller anderen Komponenten. Die meisten Komponenten sind jedoch den einzelnen physikalischen Geräte zugeordnet. Es gibt eine Tuner­Komponente, diese bildet den Tuner in unserem Framwork ab. Gleiches ist für den CD­Player, iPod und Verstärker implementiert. Alle Komponenten haben mehrere Gemeinsamkeiten, sie verfügen über Queues, die sie zu einer gepufferten Kommunikation per Events verwenden. Ein Komponente schläft solange, bis sie durch den Watchdog oder eine Nachricht in ihrer Queue geweckt wird. Nach der Abarbeitung der Nachricht wartet sie wieder blockierend auf ein Semaphor, welches mitteilt, dass eine neue Nachricht angekommen ist. Auf diese Weise wird ein unnötiges Pollen vermieden und Rechenzeit gespart. Eine Konvention des Frameworks sieht vor, alle Events über den MainDispatcher zu versenden.
2.1.4 MainDispatcher
Der MainDispatcher ist die zentrale Nachrichtenverwaltung des InCarMultimedia­Systems, dessen Queue mit einem „Briefkasten“ vergleichbar ist. Anhand der ReceiverID bzw. der FblockID und InstanceID leitet der MainDispatcher die Nachricht an die entsprechende Komponente weiter. 2.1.5 HMI (Human­Mashine­Interface)
Die Mensch­Maschine­Schnittstelle (engl. HMI) des InCarMultimedia­Systems besteht einerseits aus der Hardware, die es dem Menschen ermöglicht mit dem System zu 18
kommunizieren und andererseits aus einem Stück Software, das die Eingaben verarbeitet und entscheidet, welche Menüs etc. anzuzeigen sind. Die Hardware besteht aus einem Eingabegerät und einem Display zur Visualisierung. Die softwareseitige HMI­Komponente ist die zentrale Steuereinheit des InCarMultimedia­Systems. Sie verarbeitet die Eingaben des Nutzers und enthält die Bedienlogik. Je nach Benutzereingabe versendet sie Events an die anderen Komponenten, die daraufhin jeden Tastendruck umsetzen. Die HMI­Komponente ist im Folgenden auch als HMI bezeichnet. Anhand des Kontextes ist die verwendete Form (Hardware / Software) unterscheidbar. 2.2 MOST
Der MOST­Bus ist ein Bus zur Kommunikation zwischen verschiedenen Geräten und kann jede Art von Daten übertragen. So werden z.B. Audiodaten vom CD­Spieler zum Verstärker über diesen Bus übertragen. Der optische Bus garantiert, im Gegensatz zur elektrischen Version, beste Klangqualität, da er durch seine Massefreiheit nicht von elektrischen Strömen, dem Hauptstörungsfaktor im Automobil, beeinflusst wird. Die Daten werden in definierbaren Zeitintervallen zyklisch als Frames über den Bus versendet. In unserem Fall ist die Taktrate auf 44,1 kHz festgelegt und entspricht damit genau der Sample­Rate von CDs, damit ist die Musikwiedergabe von CDs ohne Pufferung möglich. Die Frames sind in einen synchronen, asynchronen und einen Kontroll­Kanal unterteilt. Durch die Einführung von verschiedenen Slots ist der synchrone Kanal in mehrere logische Kanäle unterteilt und ermöglicht hierdurch die gleichzeitige synchrone Kommunikation mit mehreren Geräten. Die Größe des synchronen Kanals kann ebenfalls festgelegt werden. Eine Vergrößerung hat zur Folge, dass der asynchrone Kanal verkleinert wird. Bedingt durch diese Einstellung gibt es mehr oder weniger logische Kanäle. Für spätere Betrachtungen des Frameworks ist die Adressierung der Geräte wichtig, deshalb ist es nötig, etwas tiefer in die Materie einzutauchen. 19
Wie in Abb. 1 auf folgender Seite zu sehen ist, sind alle MOST­Geräte mit zwei Lichtwellenleitern verbunden. Eine dieser Leitungen ist für das Senden, die andere für das Empfangen zuständig. Die Geräte sind in einer Ring­Topologie angeordnet und bekommen ihrer Reihenfolge nach eine DeviceID zugeteilt.
Die DeviceID ist die logische Knotenadresse und sie beginnt bei dem TimingMaster, der die Nummer 100hex erhält. Für jedes nachfolgende Gerät wird diese Zahl inkrementiert.
Abbildung 1: MOST­Devices
Oft sind in einem Gehäuse mehrere Geräte untergebracht, so gibt es z.B. Kombigeräte, die sowohl Verstärker als auch Tuner beinhalten (siehe Abb. 1). Um Nachrichten gezielt an ein bestimmtes Gerät eines Kombigerätes zu senden wird eine weitere Unterscheidungsmöglichkeit, die FunctionBlockID, benötigt. Die FunctionBlockID gibt eine Geräteklasse vor, mit der man das richtige Device ansprechen kann.
20
...
...
0x40 AmFmTuner
0x22 AudioAmplifier
0x30 AudioTapePlayer
0x41 TMC Tuner
0x24 AuxIn (Ipod)
0x31 AudioDiskPlayer
0x42 TV Tuner
0x26 MicrophoneInput
...
...
Tabelle 1: FunctionBlockID der MOST­Devices
Die FunctionBlockID's sind nicht willkürlich vergeben, sondern wie in Tabelle 1 zu sehen, in Gruppen geordnet. Die Laufwerke beginnen ab 0x30hex, Receiver ab 40hex, FunctionBlöcke, die mit der Verwaltung zu tun haben, beginnen ab 0 und Geräte zur Bedienung wie Spracherkennung und MMI beginnen ab 10hex. Weitere Geräte und Informationen sind in der MOST­Spezifikation bei http://www.mostcooperation.com zu finden.
Die Adressierung ist noch nicht beendet. Mehrere Geräte mit gleichem FunctionBlock, werden anhand der InstanceID unterschieden.
Eine MOST­Nachricht besitzt folgenden Aufbau:
DeviceID<<FBlockID<<InstanceID<<FunctionID<<OpType<<Lenght(Data)<<Data
Die FunctionID beschreibt Methoden, die auf dem Gerät gestartet werden können oder Properties, die gelesen oder gesetzt werden können. Der Optype gibt an, was damit getan wird. Möchte man z.B. den Amplifier dazu veranlassen, eine bestimmte Lautstärke einzustellen, so gibt man als FunctionID 0x400 (Volume) an, als Optype ein “SET“ (0x00) und als Daten versendet man die gewünschte Lautstärke. Die Längenangabe in einer MOST­Nachricht bezieht sich nur auf die Größe der Daten, da die restliche Größe ohnehin bekannt ist.
[WiTr­2005], [Kurz­2005]
21
2.3 Verwendete Hardware
2.3.1 InCarMultimedia­Systeme
Die in dieser Arbeit verwendeten InCarMultimedia­Systeme der Firma Harman/Becker bestehen aus MOST­Geräten (Verstärker, CD­Player, iPod, Tuner, ...) und der HMI, die ein LCD­Display zur Visualisierung und ein Eingabegerät zur Steuerung besitzt. Außerdem verfügt dieses System über eine Festplatte, Flash­Speicher, RAM, Netzwerk­Interface und weiteren Hardware­Komponenten. Als Software kommt ein Framework zum Einsatz, das an der Hochschule Darmstadt unter der Leitung von Prof. Dr. Joachim Wietzke ständig weiterentwickelt wird.
2.3.1.1 Target PON
Bei diesem in Plexiglas verbauten Target kann man die orange gefärbten Plastikfaserleitungen des MOST­Bus gut erkennen. Alle MOST­Geräte sind in einer Ring­Topologie angeordnet und mit zweien dieser Kabel verbunden, eines zum Empfangen und eines zum Senden der Daten. Oben in der Mitte des Bildes (zwischen den MOST­Leitungen) befindet sich eine Adapterplatine, die den Apple ­ iPod Abbildung 2: InCarMultimedia­System (Target PON)
zu einem MOT­Gerät werden lässt.
22
2.3.1.2 Target NG3
Dieses Target verfügt über einen Renesas Hitachi Super­H 4 Prozessor (SH4) mit 400 MHz, eine Realtek 100 MBit Netzwerkkarte, eine Grafikkarte mit Coral­Chip, der sowohl 2D­ als auch 3D­Funktionen unterstützt. Außerdem besitzt dieses Target einen zweiten Prozessor (ST10), der mit dem seriell angeschlossenen Bedienteil und dem MOST­Bus kommuniziert. Zusätzlich verfügt dieses Target über Bluetooth, WLAN und Kartenleser. Das Liquid Crystal Display besitzt eine Größe von 800 Pixeln Breite und 480 Pixeln Höhe. Ein DVD­Player löst den CD­Player, der in dem älteren PON­Target ist, ab.
Abbildung 3: InCarMultimedia­System (Target NG3)
23
2.3.2 Remote Geräte
2.3.2.1 HP­iPAQ h5500
Der HP­iPAQ h5500 ist ein Persönlicher Digitaler Assistent (PDA), der, mit dem mitgelieferten Betriebssystem MS Pocket PC 2003 und PIM­
Tools eine gut ausgereifte Software­Basis bietet. Als CPU kommt ein Intel XScale Prozessor mit 400 MHz zum Einsatz. Das Display hat eine Größe von 240x320 Pixel und kann 65536 Farben darstellen. Dass es sich bei diesem Display um einen Touchscreen handelt, ist für die Betrachtung der Steuerung in späteren Kapiteln von Bedeutung. Mit Bluetooth und WLan ausgerüstet, ist der iPAQ perfekt für eine remote Steuerung geeignet. Auf weitere Hardwaremerkmale wie z.B. den Slot für SD­Speicherkarten etc. wird nicht Abbildung 4: HP­iPAQ h5500 (Pocket PC) aus [hp­2006]
eingegangen, da sie für das Vorhaben nicht benötigt werden.
2.3.2.2 Siemens S65 Mobiltelefon
Das Siemens S65 Handy soll als weitere HMI eingesetzt werden. Mit einem Display von 132x176 Pixel Größe und 16Bit Farbtiefe, Bluetooth und der JAVA­Fähigkeit ist es ebenfalls für den Einsatz geeignet. Die geplante Software soll auf allen JAVA fähigen Handys, die Bluetooth besitzen, lauffähig sein und nicht auf dieses Handy beschränkt werden. Abbildung 5: S65 (aus [Drex­2006])
24
3 Konzept
3.1 Framework im Ausgangszustand
Um das in der Arbeit entwickelte Konzept und die gewählten Wege zu verstehen, ist es von Vorteil die Ausgangssituation zu kennen. In dem bestehenden InCarMultimedia­Framework sind etliche Komponenten vorhanden. Alle Komponenten laufen als unterschiedliche Prozesse, die über Queues miteinander kommunizieren. Die Queues sind im Shared­Memory vereinbart; dadurch ist es möglich über Prozessgrenzen hinweg miteinander zu kommunizieren. Alle Nachrichten werden wie zuvor beschrieben über den MainDispatcher versandt. Die Komponenten, die physikalische MOST­Geräte wie den Tuner abbilden, sind in einen Controller, ein LogDev und einen Proxy unterteilt. Der Proxy eines MOST­Gerätes bildet dessen Funktionalitäten ab. Falls beispielsweise ein CD­Spieler den Befehl Scan nicht kennt, wird dieser durch das logische Device (kurz LogDev) nachempfunden, indem dieses eine Folge niederer Befehle an den enthaltenen Proxy versendet. In bestimmten Situationen ist es manchen dieser MOST­Geräte nicht möglich, alle theoretisch denkbaren Aktionen auszuführen, so könnte es z.B. sein, dass es einen CD­Spieler gibt, der im Play­Modus keine CDs auswerfen kann. Der Controller verhindert mit seiner State­Machine, in solche nicht erlaubten Zustände zu wechseln.
Das InCarMultimedia­System besitzt in der Ausgangssituation einen CD­Spieler, einen iPod, einen Tuner und einen Verstärker, die als MOST­Geräte an der Head­Unit angeschlossen sind. Die Head­Unit ist die Haupt­Platine, an der das Bedienteil und ein LCD­Display angeschlossen sind. Softwareseitig gibt es eine HMI­Komponente, die die Tastendrücke des Bedienteils verarbeitet und die Grafik anzeigt. Alle im Framework vorhandenen Geräte hören auf die Befehle der HMI, die als alleinige Komponente das Sagen hat. Der MOST­Treiber, der die MOST­Nachrichten über den Bus versendet hat eine feste Zuordnung von FunctionBlockID und DeviceID's, da alle Target­Systeme gleich aufgebaut sind.
25
3.2 Das InCarMultimedia­System im Wandel
Zu Beginn dieses Projektes wurde der Hardwarestand erneuert. Zu dem bereits vorhandenen Target PON kam ein komplett neues Target hinzu, welches von unserem Framework ebenfalls unterstützt werden sollte. Aber auch an dem bisherigen Target wurden Veränderungen vorgenommen, so besaß das Target bisher eine HMI und einen Verstärker. Dazu kamen mehrere Abspielgeräte, von denen aber nur eins zur Zeit spielt. Nach dem Wandel besitzen die beiden Target­Typen jeweils zwei Verstärker und mehrere Abspielgeräte, die nun auch parallel spielen sollen. Mit dieser Masterarbeit soll ein Konzept entwickelt werden, das es erlaubt, mehrere HMIs gleichzeitig zu betreiben, denn ohne ein geeignetes Konzept ist ein Chaos unvermeidbar. Folgende Tabelle zeigt die bereits vorhandenen, bzw. die in der Entwicklung stehenden HMIs. Die hervorgehobenen entstanden durch diese Masterthesis.
Ausgabe
Eingabe
Plattform
OpenGL ES
Maxicom
sh4 QNX Target­NG3
Photon
Minicom
sh4 QNX Target­PON
Qt/Embedded
Pen
X­Scale Linux HP­iPAQ (Remote)
OpenGL
Tastatur bzw. Maxicom Keys über x86 Linux PC / Keys über NG3
Socket
(Remote)
Qt/X11
Tastatur und Maus x86 Linux PC (Remote)
Java2ME
Softkeys + Numpad
Mobiltelefone (Remote)
Tabelle 2: In der Entwicklung stehende HMIs
Nach der Erneuerung des Hardwarestandes gibt es mehrere Verstärker im folgenden Amplifier oder kurz Amp genannt. Der erste im MOST­Bus vorhandene Verstärker soll für die Auto­Lautsprecher zuständig sein, der zweite für den Kopfhörerausgang im Rücksitz­
Bereich.
Die vorhandenen Abspielgeräte, wie z.B. der Tuner, der CD­Player und der Ipod haben eine Gemeinsamkeit: Diese Geräte können alle nicht mehrere Lieder bzw. Sender zur gleichen Zeit abspielen. Des Weiteren sollen mit dieser Arbeit neue HMIs eingeführt werden, die parallel im Framework agieren. 26
Die Verwaltung eines Verstärkers und beliebig vieler Abspielgeräte, von denen nur eines zur Zeit spielte, war bisher denkbar einfach. Die einzige im Framework vorhandene HMI, die vom Fahrer bzw. von dem Beifahrer des Wagens gesteuert werden konnte, entschied darüber, mit welchem Abspielgerät der Verstärker verbunden werden sollte.
Im bisherigen Stand der Software wurden die, für die einzelnen Abspielgeräte reservierten Kanäle, fest im Quellcode des Amplifiers verankert. Um zu einem anderen Abspielgerät zu wechseln, schickte die HMI bisher eine Nachricht mit der Komponenten­ID an den Verstärker, der mithilfe eines “Switch“­Statements entschied, auf welche Kanäle er zugreifen sollte. Dies hatte zur Folge, dass der Verstärker jedes Abspielgerät und dessen reservierte Kanäle kennen musste. Würde man einen weiteren Verstärker hinzufügen, müsste dieser ebenfalls das gleiche Wissen über die vorhandenen Komponenten mitbringen. Redundant vorhandene Daten wären die Folgen daraus. Würde man zusätzlich ein weiteres Abspielgerät in das Framework integrieren, müssten alle Verstärker um dieses Wissen über die Komponente und deren Kanäle erweitert werden.
Das neu konzipierte Framework soll es ermöglichen, mit so wenig Aufwand wie möglich beliebig viele Komponenten hinzufügen zu können. Im bisherigen Framework war eine „1 zu N“­Beziehung von Verstärker zu Abspielgeräten vorhanden, über die eine HMI entschied, welche Verbindung zustande kommen sollte.
Das neue Framework soll eine “N zu M“­Beziehung von Verstärkern zu Abspielgeräten verwalten können. Bei mehreren parallel vorhandenen HMIs, die von verschiedenen Personen bedient werden, ist es verständlich, dass Konflikte auftreten. Betrachtet man hierzu nur das allabendliche Fernsehprogramm, über das sich viele Familienmitglieder kaum einigen können. In dem vorhanden Framework muss geklärt werden, wer über welche Geräte steuerbefugt ist. Um die Frage der Steuerbefugnis zu klären ist es nötig, Verwaltungscode in das Framework zu integrieren. Zum einen muss dieser Verwaltungscode entscheiden, welche Verbindungen von Verstärkern zu Abspielgeräten stattfinden sollen und zum anderen muss geklärt werden, welche HMI das Abspielgerät steuern darf. Als es nur eine HMI gab, entschied diese darüber was geschah. Welche Verbindungen zustande kommen sollten und welches Lied oder welchen Sender das Abspielgerät spielte, entschied sie allein.
27
3.2.1 Die Unterbringung der Verwaltung in einer Remote­HMI
Die Rechtebeschränkung bzw. die Regelung der Steuerbefugnis kann man auf keinen Fall in einer der Remote­HMIs unterbringen, da diese nicht zwangsweise mit dem Target verbunden sind. Wenn man die Regelung der Rechte in einer Remote­HMI unterbringen könnte, hätte man den Vorteil, dass man am Framework nur minimale Änderungen vornehmen müsste.
Die Remote­HMI wird ohnehin neu entwickelt und man könnte dort diesen Verwaltungscode einfügen. Aus oben genannte Gründen ist dies aber nicht möglich. Für jede Remote­HMI ist auf Target­Seite eine Komponente vorgesehen, die alle Nachrichten der Remote­HMI entgegennimmt. Diese Komponente könnte ebenfalls überprüfen, ob der gerade erhaltene Befehl zulässig ist.
3.2.2 Die Unterbringung der Verwaltung in der lokalen HMI
Man könnte sich überlegen die lokale HMI, die bisher für das Zustandekommen der Verbindungen zuständig war, um den Programmcode der Verwaltung zu erweitern.
Mit dem Einführen des neuen Targets ist eine neue HMI hinzugekommen. Das ältere Target PON besitzt eine Photon Grafik, das neuere Target besitzt eine Grafik, die in OpenGL ES realisiert wurde. Durch die unterschiedlichen Bedienteile der Targets und deren Möglichkeiten entstand ein anderer Menübaum, dadurch sind die beiden HMIs so unterschiedlich, dass sie in zwei verschiedenen Ordnern untergebracht wurden. Je nachdem für welches der beiden Target­Typen das Programm erstellt wird, wird eine der beiden lokalen HMIs beim Übersetzungsvorgang nicht berücksichtigt. Wenn man den Verwaltungs­Code nur in eine der beiden HMIs stecken würde, dann gäbe es bei dem anderen Target keine Verwaltung. Dieser Verwaltungs­Code muss also entweder in beide HMIs, was eine Codeverdopplung und schwere Pflege zur Folge hätte oder man muss den Code geschickt von beiden HMIs includieren, um dieses Problem zu vermeiden.
Eine Remote­HMI besitzt den Vorteil, dass man sie bei neuen Targets einsetzen kann, für die noch keine grafische Oberfläche entwickelte wurde. In solchen Fällen, bei denen es also noch keine lokale HMI gibt, gilt es trotzdem zu regeln, welche HMI steuerbefugt ist. Wer regelt in dem Fall die Rechte, wenn zwei Remote­HMIs miteinander konkurrieren. Entweder 28
muss es immer eine lokale HMI geben oder der Verwaltungscode sollte an einer anderen Stelle untergebracht werden.
Um Abstraktion zu erreichen muss man entscheiden, was in die HMI gehört und was nicht. Dazu ist es nötig, alle HMIs zu vergleichen und die Gemeinsamkeiten herauszustellen. Während dieser Überlegungen bin ich zum Entschluss gekommen, dass man die Rechte der Ressourcenverwaltung an einer Stelle regeln muss. Wenn die Vergabe der Rechte also an nur einer Stelle untergebracht werden darf, dann kann die Vergabe der Rechte kein Bestandteil der HMI sein da diese alle prinzipiell gleich sind und es mehrere davon gibt. „Perfektion ist nicht dann erreicht, wenn man nichts mehr hinzufügen kann, sondern wenn man nichts mehr wegnehmen kann.“
Antoine de Saint­Exupéry
Dieser Satz von Antoine de Saint­Exupéry ist gerade bei Abstraktionen zu berücksichtigen. Der Verwaltungscode ist also aus der HMI zu entfernen.
Das Konzept sieht vor, die HMIs grundsätzlich gleich zu gestalten.
Jede HMI ist nur für die Ein­ bzw. Ausgabe zuständig und hat also keine Verwaltung zu regeln. Der Controller incl. State­Machine der lokalen HMI, der bisher für die Verwaltung zuständig gemacht wurde, ist nun nur für Übergänge beim Menüwechsel zuständig. Die unterschiedlichen Menüstrukturen der verschiedenen HMIs benötigen eine unterschiedliche Behandlung. Auf diese Aufgabe soll der HMI­Controller beschränkt werden. 3.2.3 Die Unterbringung der Verwaltung in einer neuen Komponente
Eine HMI soll nicht wissen müssen, mit wie vielen anderen HMIs sie in Konkurrenz steht. Jede HMI kennt nur diese neue Komponente, in der der Verwaltungscode für alle Verbindungen und Ressourcen untergebracht wird. Die neue Komponente wird “AudioMaster“ getauft, da sie für alle Audio­Geräte regelt, wer sie bedienen darf. Dieser, den HMIs übergeordnete Controller regelt ebenfalls, welche Quellen und Senken verbunden 29
werden.
Das folgende Schaubild zeigt alle HMIs, die nun durch den AudiMaster von den Abspielgeräten und Verstärkern getrennt sind. Die HMIs entscheiden nun nicht mehr, welche Verbindungen zustande kommen, sondern äußern nur noch Verbindungswünsche gegenüber dem AudioMaster. Dieser entscheidet darüber, welche Verbindungen eingegangen werden und vermerkt sich die Verbindungen in einer Registry (siehe Abb. 6). Abbildung 6: AudioMaster zur Ressourcen Verwaltung
30
3.2.4 Designentscheidungen der einzelnen Komponenten
Das neu erstellte Konzept geht auf Designentscheidungen ein, denn es ist wichtig, dass die einzelnen Komponenten neu durchdacht werden.
3.2.4.1 Amplifier Im Framework soll es jeweils eine Komponente pro Amplifier geben; wenn eine dieser Komponenten abstürzt, soll die andere unabhängig davon weiter laufen können. Jeder Amplifier hat dadurch seinen eigenen Kontext incl. Queues. Das Konzept sieht vor, jeder Komponente bei der Initialisierung eine Referenz auf einen MostProxy zu übergeben (siehe Listing 1). Vorteile dabei sind, dass die Komponente und das enthaltene Logische­Device (kurz LogDev) gleich bleiben und nur der Proxy, der den Stellvertreter für das physikalische Gerät darstellt, neu geschrieben werden muss. Auf MOST­Seite funktionieren die beiden verwendeten Verstärker unterschiedlich. Damit das LogDev und die Komponente für beide Verstärker gleich bleiben können, müssen die Proxies nach außen einheitliche Funktionen bieten. Deshalb werden die Proxies von einer gemeinsamen Basisklasse, der CAmpMostProxy­Klasse abgeleitet, welche den Standard­
MOST­Katalog als Implementierungsgrundlage verwendet (siehe Abb. 7). Diese Klasse ist wiederum von der CMostProxyBase­Klasse abgeleitet, welche die grundlegenden Gemeinsamkeiten aller MOST­Geräte enthält. Dazu gehört das Decodieren von einzelnen Datentypen etc.. Die Abweichungen vom Standard­MOST­Katalog werden in den jeweiligen Proxies durch Reimplementieren der betroffenen Funktionen der CAmoMostProxy­Klasse bereinigt.
31
Abbildung 7: MostProxy Inheritance Graph
Der zweite Verstärker, der für den Kopfhörerausgang zuständig gemacht wird und zusätzlich an die Targets PON und NG3 angeschlossen wird, ist bei beiden Targets das gleiche Modell, so ist keine Unterscheidung nötig. Der erste Verstärker, der im MOST­Ring vorhanden ist, ist bei den Targets PON und NG3 unterschiedlich, dadurch ist eine Unterscheidung im Framework nötig. Die Proxies sind nach den Target­Systemen benannt, in denen sie standardmäßig verbaut sind. Da man den Verstärker der PON auch an die NG3 anschließen kann, sind die Bezeichnungen CAmpNG3MostProxy und CAmpPonMostProxy irreführend gewählt. Des Weiteren ist es nötig, dass jeder Verstärker einen eigenen Datencontainer besitzt, da die Sound­Einstellungen getrennt geregelt werden sollen (siehe Listing 1).
//...
else if (fork() == 0)
{
// instance of Datacontainer
CAmpDC ampDC0(*CContext::getAmpDCShared(0));
#ifdef _TARGET_PON_
CAmpPonMostProxy Amp0MostProxy(1, Amp0ID, ampDC0);
#endif //_TARGET_PON_
#ifdef _TARGET_NG3_
CAmpNG3MostProxy Amp0MostProxy(1, Amp0ID, ampDC0);
#endif //_TARGET_NG3_
CAmpComponent ampPon(CContext::getAmp0Context(),&Amp0MostProxy,Amp0ID);
32
CThread thread(ampPon, "AmpPon", Ccontext::AMP_0_STACK_SIZE,
CContext::AMP_0_PRIORITY, true);
thread.start();
}
else if (fork() == 0)
{
// instance of Datacontainer
CAmpDC ampDC1(*CContext::getAmpDCShared(1));
CAmpNG3MostProxy Amp1Mostproxy(2, Amp1ID, ampDC1);
CAmpComponent ampNG3(CContext::getAmp1Context(),&Amp1Mostproxy,Amp1ID);
CThread thread(ampNG3, "AmpNG3", Ccontext::AMP_1_STACK_SIZE,
CContext::AMP_1_PRIORITY, true);
thread.start();
}
//...
Listing 1: Forken der Amplifier in der AdminComponent.cpp In der Admin­Komponente, in der die beiden Amplifier­Komponenten erzeugt und gestartet werden, wird anhand der Defines _TARGET_NG3_ und _TARGET_PON_ unterschieden, welcher Proxy zum Einsatz kommt (siehe Listing 1). Das erstellte Konzept sieht vor, dass die Verstärker nichts über die im Framework vorhandenen Abspielgeräte wissen müssen. Dadurch ist eine leichte Erweiterbarkeit sichergestellt. Falls Verbindungen stattfinden sollen, werden den betreffenden Verstärkern die zu verwendenden Kanäle mitgeteilt.
3.2.4.2 Abspielgeräte
Da die Abspielgeräte, wie z.B. der CD­Player oder der Apple­iPod nur ein Lied zur Zeit abspielen können, muss geregelt werden, wer vorgibt, was zu spielen ist. Der AudioMaster erteilt dazu einer HMI eine Steuerberechtigung. Es soll jedoch möglich sein, das gleiche Lied auch über den zweiten Verstärker zu hören.
Eine HMI soll das Recht bekommen, z.B. die Track­Nr. beim CD­Player zu ändern oder den Sender beim Tuner zu verstellen. Alle anderen HMIs können als Slaves fungieren und das gleiche Lied an einem anderen Verstärker abspielen. Hierdurch soll es den Kindern auf den 33
Rücksitzen ermöglicht werden, das gleiche Lied zu hören. Sie können die Lautstärke auf ihrem, für den Kopfhörer zuständigen Verstärker, selbst steuern. Ebenso ist es ihnen möglich, Bass, Treble oder andere Sound­Einstellungen individuell zu regeln. Für alle gerade nicht genutzten Abspielgeräte können sie die Rechte beim AudioMaster anfordern und so als Master für dieses eine Gerät fungieren (siehe Abb. 6). 3.2.4.3 MOST­Treiber
Der MOST­Treiber ist dafür zuständig, die MOST­Nachrichten, die innerhalb des Framworks nur mit der FunctionBlockID und der InstanceID adressiert sind, an das richtige Gerät zu senden. Die Empfängeradresse der MOST­Nachricht muss um das Feld DeviceID erweitert werden. Wenn man eine feste Konfiguration von MOST­Geräten im InCarMultimedia­
System hat, ist die Zuordnung sehr einfach. Man kann mit dem Mostolyzer (einem Analyse­
Gerät für MOST­Busse, die Daten betrachten, die über den Bus versendet werden. Hierdurch erfährt man, dass beispielsweise der CD­Player die DeviceID 0x102 zugeteilt bekam. Dieser hat die FblockID 0x31 und nun sollte es kein Problem sein ihn folgerichtig zu adressieren.
Der Hardwarestand hat sich mittlerweile geändert und der MOST­Treiber muss ebenfalls das neue Target NG3 unterstützen. Die oben genannte Analyse­Methode mit Hilfe des Mostolyzer kann auch hier angewendet werden. Ein paar “#ifdef“­Zeilen könnten die Unterscheidung zwischen PON und NG3 bewerkstelligen. Für die Entwicklung des Multi­HMI­Konzeptes wurden zusätzliche Verstärker an die Targets angeschlossen. An einigen Targets ist zusätzlich ein iPod oder ein CD­Wechsler hinzugefügt worden. Es gibt nun kaum noch Targets mit den gleichen MOST­Geräte in der selben Reihenfolge am Bus. Dadurch ist eine feste Zuordnung von FunctionBlockID und InstanceID zur DeviceID nicht mehr möglich. Um dieses Problem zu umgehen, könnte man eine Konfigurationssoftware schreiben, der man mitteilt, um welchen Target­Typ es sich handelt und welche Devices in Netz vorhanden sind. Abhängig davon kann man die Komponenten softwareseitig in das Framework integrieren. Falls beim Verbinden der MOST­Leitungen eine gewisse Reihenfolge eingehalten würde, so stünden die DeviceIDs zu Compilezeit fest.
Falls ein Kunde nachträglich einen CD­Wechsler eingebaut haben möchte, kann er dies nicht selbstständig durchführen, da ein Software­Update nötig wäre. In dem vorhandenen InCarMultimedia­Framework werden die Komponenten immer mit aufgenommen. 34
Die IPod­Komponente ist immer ein fester Bestandteil der Software, auch wenn kein iPod am Target angeschlossen ist. Eine zweite Verstärker­Komponente ist ebenfalls immer Bestandteil der Software. Die Nachteile hiervon sind, dass der Context für diese Komponenten vorhanden ist und deshalb Speicherplatz verbraucht wird. Der Watchdog verbraucht zusätzliche Rechenzeit, um eine Komponente zu überwachen, die als Hardware nicht vorhanden ist. Die Komponente selbst verbraucht nur minimal Rechenzeit, da sie die meiste Zeit blockierend auf Daten wartet.
Das Konzept sieht vor, dass das Framework mit einer variablen Konfiguration von Geräten im MOST­Ring zurecht kommen muss. Dafür ist es nötig, die DeviceIDs zur Laufzeit zu ermitteln. Hierbei hilft uns der FunktionBlock NetBlock, der Bestandteil jedes MOST­
Gerätes ist. Über den Netblock lassen sich die anderen FunctionBlockID's auslesen, somit ist der Typ des Gerätes erkennbar. Eine Registry wird softwareseitig aufgebaut, die eine Zuordnung von DeviceID zu FunctionBlock und InstanceID bewerkstelligt.
UInt16
UInt16
UInt16
UInt16
UInt16
mDevTuner1;
mDevAmp1;
mDevAmp2;
mDevIPod1;
mDevCD1;
Listing 2: Variablen zur Zuordnung von FunctionBlockID und InstanceID zu DeviceID In unserem Fall ist die Registry einfach gehalten. Die Variable mDevAmp2 steht für den zweiten Amplifier, der den FunctionBlock 0x20 und die InstanceID 0x2 besitzt. In der Variablen mDevAmp2 ist die zugehörige DeviceID (logische Knotenadresse) vermerkt, somit ist eine Zuordnung möglich. Für alle anderen MOST­Geräte ist diese auf äquivalente Weise realisiert.
3.2.4.4 Ist­ und Soll­Datencontainer
Der Ist­Datencontainer hält die gerade aktuellen Informationen eines Gerätes. Dieser gehört zum Gerät. Beim Beispiel eines CD­Changers ist im DatenContainer vermerkt, welche CD und welches Lied gerade spielt. Ein Soll­DatenContainer hingegen gibt vor, welche CD und welches Lied gespielt werden soll. Als es bisher nur eine HMI gab, entschied man das der 35
Soll­Datencontainer zum entsprechenden Device gehört und dieses die beide Container abgleichen soll. Ein Szenario mit zwei HMI sei angeführt, das zu Überlegungen anregt.
Szenario:
HMI1 wird als HMI mit höchster Priorität und HMI2 als HMI mit geringerer Priorität konfiguriert. HMI1 hört beispielsweise Radio auf der Frequenz 102,9. Die HMI besitzt die Steuerbefugnis über dieses Gerät. HMI2 hört auf einem anderen Verstärker (Verstärker2) mit. HMI1 wechselt nun ins CD­Menü. Hieraus folgt: HMI2 ist die HMI mit höchster Priorität, die Tuner und Verstärker2 verbunden hat.
HMI2 bekommt die Steuererlaubnis für den Tuner. Für den Verstärker2 hatte sie bereits Steuererlaubnis, da keine andere HMI ihn benutzte. Nun wechselt HMI1 wieder zurück nach Tuner. Die Folgen davon sind:
Die Steuererlaubnis der HMI2 über den Tuner erlischt.
HMI1 ist wieder steuerberechtigt.
Bis dahin scheint alles gut zu laufen. Wenn HMI2, als sie Steuerberechtigt war, den Sender gewechselt hat, so ist dieser auch für HMI1 verstellt. Wenn man also wieder zum ursprünglichen Sender zurück springen möchte, muss man sich den Sender merken. Gleiches gilt für CD­Changer und andere Geräte. Wenn man sich dieses Szenario anschaut und weitere Umschalt­Szenarien durchspielt, wird man zum Ergebnis kommen, dass jede HMI ihren eigenen Soll­DatenContainer benötigt. Man kann auch auf die Vielzahl der DatenContainer verzichten, wenn man in Kauf nimmt, dass nach dem Umschalten der Sender oder das Lied der CD verstellt sein können.
36
3.2.5 Implementierung des AudioMasters
Es gibt viele Möglichkeiten, wie man einen solchen AudioMaster implementieren könnte. Kurz seien einige Designentscheidungen angeführt und deren Vor­ bzw. Nachteile herausgestellt. 3.2.5.1 Übergangstabelle
Eine Tabelle regelt für jede Ressource und HMI, wer bevorzugt behandelt wird. Ein Vorteil dieses Verfahrens ist, dass eine HMI bei einer Resource bevorzugt behandelt werden kann, bei einer anderen Resource dagegen benachteiligt wird. Dadurch ist eine sehr genaue und für jedes Gerät individuelle Möglichkeit der Ressourcenzuteilung gegeben. Man könnte z.B. die Remote­HMI bei der Vergabe vom Kopfhörer­Verstärker bevorzugen, sie aber bei anderen Funktionen benachteiligen.
Dieses Verfahren ist nur dann möglich, wenn man von Anfang an weiß, welche Geräte und welche HMIs im Framework vorhanden sind. Diese mögliche Implementierung ist schlecht erweiterbar und das Hinzufügen von neuen Geräten bedeutet zugleich, dass das Programm bzw. die Tabelle geändert werden muss.
3.2.5.2 Prioritätssystem
Jede HMI bekommt vom AudioMaster eine Priorität zugewiesen. Remote­HMIs bekommen eine geringere Priorität als die lokalen HMIs. Denn die Remote­Geräte sollen in Konfliktfällen benachteiligt behandelt werden. Am konkreten Beispiel würde dies bedeuten, dass derjenige, der das InCarMultimedia­System vom Rücksitz aus bedienen möchte, weniger Rechte zugesprochen bekommt, als der Fahrer des Wagens. Das Prioritätssystem soll mit neuen Komponenten keine Probleme haben und dadurch flexibel erweiterbar sein. Es gibt keine festen Vorgaben, welche Geräte im System vorhanden sein sollen. Um diese Flexibilität zu erreichen, ist es nötig, dass sich die Geräte beim AudioMaster anmelden. Für alle Abspielgeräte gibt es ein High­Level­Event in Form einer Application­Message, die als Optype REGISTER_SOURCE verwendet.
37
Alle Geräte mit einer Audioquelle allokieren bei der Initialisierung ihre Kanäle. Diese geben sie beim Registrieren als Parameter mit an den AudioMaster. Außerdem werden auch SourceNr und SourceDelay dem AudioMaster übergeben. Die Geräte mit einer Senke melden sich ebenfalls beim AudioMaster an. Anstelle des Optypes REGISTER_SOURCE verwenden sie REGISTER_DESTINATION. Im Normalfall sind dies Audioverstärker, man könnte aber auch z.B. einen Harddisk­Recorder für Audiodaten implementieren. Dieser könnte Telefongespräche mitschneiden, Radiosender aufzeichnen oder CD­Inhalte auf Festplatte speichern. Durch einen solchen Recorder wäre beispielsweise das Digitalisieren von Tapes möglich. Für die HMIs gibt es ähnliche Funktionen zum Anmelden beim AudioMaster. Der AudioMaster baut eine Registry auf. In einer Art Tabelle wird gespeichert, welche Geräte gerade verbunden sind. Grob könnte diese so aussehen.
HMI
SOURCE
DESTINATION
HMI1
iPod
Amp2
HMI2
Tuner
Amp1
Tabelle 3: Connection Registry
Durch die, in Tabelle 3 gezeigte Registry vermerkt sich der AudioMaster die Verbindungen. Update­Nachrichten könnten so gezielt an die jeweiligen HMIs versendet werden. Beispiel:
Die Tuner­Komponente versendet Radiotext, weiß aber nicht, an welche HMIs sie die Update­Nachricht senden soll. Eine Möglichkeit wäre, diese Update­Nachricht an den AudioMaster zu leiten. Dieser vermerkt sich, welche HMI sich gerade im Tuner­Menü befindet und sendet den Radiotext gezielt an diese Komponente weiter. Die Update­Nachricht eines CD­Player, der gerade meldet, dass sein Lied zu Ende ist und ein neues beginnt, könnte auf die gleiche Weise bearbeitet werden.
Das Konzept sieht es bisher nicht vor, die Update­Nachrichten auf dieses Weise zu versenden, da es der HMI auch möglich sein soll im CD­Menü beispielsweise Radiotext anzeigen zu können.
38
Für die Registry aus Tabelle 3 sind einige Überlegungen anzustellen. Damit der Verstärker nicht alle Abspielgeräte kennen musss, werden ihm die zu verwendenden Kanäle vom AudioMaster mitgeteilt. Um diese Unabhängigkeit zu erreichen ist es nötig, dass der AudioMaster alle Abspielgeräte und deren Kanäle kennt. Für jede Verbindung muss er sich merken, welcher Verstärker mit welchem Abspielgerät verbunden ist. Des Weiteren ist es nötig zu wissen, welche HMI diese Verbindung veranlasst hat, damit in Konfliktfällen die Priorität der HMI entscheidet was zu tun ist. Zu jedem Abspielgerät werden weitere Parameter wie z.B. SourceDelay vermerkt. HMI Priorität Destination
Source
SourceNr. SourceDelay ChannelList
HMI1 5
Amp1
Tuner
1
0
0,1,2,3
HMI2 10
Amp2
Tuner
1
0
0,1,2,3
HMI1 5
Amp3
iPod
1
2
4,5,6,7
Tabelle 4: Registry nicht normalisiert
Um nicht wie in Tabelle 4 die Daten redundant zu halten, sieht das Konzept vor, die Daten zu normalisieren. Im Fall der vorherigen Tabelle sieht man, dass die Kanal­Liste der Abspielgeräte sowie die Priorität der HMIs mehrfach gespeichert werden.
In dem aufgezeigten Fall ist die Steuerbefugnis nicht enthalten. Sie müsste ebenfalls in der Tabelle ergänzt werden. HMI2 bekommt Steuerbefugnis über den Tuner und den zweiten Verstärker (Amp2), da sie die HMI mit höchster Priorität ist die den Tuner für sich beansprucht. Der HMI1 wird es ermöglicht, ebenfalls Radio zu hören, sie darf aber keinen Senderwechsel vornehmen. Sie darf den Amp1, den Amp3 und den iPod steuern.
Durch die Normalisierung der obigen Tabelle, entstehen weitere Tabellen, die wie folgt aussehen.
ID HMI
Priorität (prio)
0
HMI1
5
1
HMI2
10
Tabelle 5: HMI­Tabelle
39
ID Destination ID der steuerbefugten HMI
0
Amp3
0
1
Amp1
0
2
Amp2
1
Tabelle 6: Destination­Tabelle
ID Source
SourceNr. SourceDelay Channel ID der steuerbefugten HMI
0
Tuner
1
0
0,1,2,3
1
1
iPod
1
2
4,5,6,7
0
Tabelle 7: Source­Tabelle
HMI­ID
Source­ID
Destination­ID
0
0
1
1
0
2
0
1
0
Tabelle 8: Registry­Tabelle
Wie in Tabelle 6 zu sehen sind die Geräte nicht in der Tabelle sortiert, sondern der Reihenfolge nach eingeordnet, in der sie sich beim AudioMaster anmeldeten. Für die Umsetzung dieser Tabellen in Quellcode gibt es verschiedene Möglichkeiten. Man könnte sowohl Klassen als auch Structs verwenden. Eine Liste von HMIs könnte als ein Array von einem Struct abgebildet werden. Der Struct enhält die Komponenten­ID der HMI und deren Priorität. Die ID­Spalte der Tabelle ist mit dem Index des Arrays äquivalent. Anstelle eines Structs könnte ein Klasse verwendet werden. 3.2.5.3 Class vs. Struct
Speicherplatz
Da die Methoden einer Klasse für alle Objekte nur einmal benötigt werden, fällt der mehr benötigte Speicherplatz kaum ins Gewicht. Falls man keine Methoden hat, ist der benötigte Speicherplatz exakt der gleiche. Ein Objekt einer virtuellen Klasse ist etwas größer, da es zusätzlich einen Pointer auf die V­Table besitzt. In unserem Fall wäre jedoch keine virtuelle Klasse nötig.
40
Geschwindigkeit
Die Zugriffe über Set­ und Get­Methoden sind langsamer als der direkte Zugriff auf einen Struct. Public Deklarationen der Membervariablen erlauben ebenfalls die gleiche Zugriffsgeschwindigkeit. Daten­Kapselung
Bei einer Klasse ist es möglich Datenkapselung durch private Deklaration der Member­
Variablen zu erreichen. Jedoch ist dann ein Nachteil bei der Geschwindigkeit zu verbuchen, da es nötig ist, über Setter­ und Getter­Methoden auf die Daten zuzugreifen.
Der AudioMaster ist eine eigenständige Komponente, die als eigener Prozess läuft. Eine gewisse Datenkapselung ist hierdurch bereits gegeben. Keine andere Komponente hat direkten Zugriff auf diese Structs oder Klassen. Die zuvor beschriebene Registry­Tabelle benötigt Daten aus allen drei Klassen oder Structs. Die Folgen hiervon sind:
Es gibt wieder Set und Get Methoden, die die Geschwindigkeit beeinflussen. Oder Public Deklarationen von Member­Variablen, die die Datenkapselung zunichte machen.
Um beides zu vermeiden, könnte man die Registy als Friendklasse implementieren.
Eine Friendklasse ist eine Aufweichung der Datenkapselung. Die strikte Datenkapselung bei Klassen wäre der einzige Vorteil gegenüber der Verwendung von Structs.
Bei der Implementierung wurden Structs verwendet. Letztendlich muss jeder für sich entscheiden, was er bevorzugt.
Die HMI­Tabelle müsste abstrakter betrachtet werden, denn nicht nur der Benutzer kann einen Wechsel von Audioquellen mit dem Verstärker veranlassen, sondern auch das System selbst. Die Navigationskomponente möchte beispielsweise eine Ansage machen und benötigt hierfür einen Verstärker incl. Lautsprechern. In einem anderen Fall möchte die Navigationskomponente den TMC­Tuner beanspruchen, um so Staumeldungen zu empfangen. Es ist ebenfalls denkbar, dass die Telefonkomponente einen Anruf entgegennimmt und dafür die Lautsprecher belegen möchte. In einem InCarMultimedia­
Framework sind nicht nur HMIs steuerbefugt, sondern auch andere Komponenten können an die Stelle der HMI treten.
41
3.2.5.4 Umschaltlogik
Geräte, die nicht verwendet werden, können von jeder HMI verbunden werden, gleichgültig welche Priorität sie besitzen. Wenn eine HMI mit höherer Priorität einen Wechsel von Sourcen veranlasst, die bereits verbunden waren, wird dieser Wechsel vollzogen.
Möchten zwei HMIs Tuner nach Amp1 verbinden, so ist dies zulässig, beide werden in der Registry aufgenommen. Die HMI mit höherer Priorität bekommt die Steuererlaubnis.
3.2.6 Anbindung der Remote­HMI
Die Remote­HMI soll als neue Komponente in das Framework integriert
werden.
Die Komponenten in Abbildung 8 sind nach ihren Komponenten­
IDs, wie sie in der Global.h definiert sind, benannt. Um die Kommunikation zum iPAQ zu ermöglichen, ist in das Framework ein Komponente mit der ID “wLanServerID“ eingefügt worden. Diese Komponente wird im folgenden WLanServer genannt. Der WLanServer versendet alle Abbildung 8: Anbindung der Remote­HMI an das Framework
Nachrichten von und zur Remote­
HMI. Das Konzept sieht vor, alle HMIs einheitlich zu gestalten. Aus der Sicht des Frameorks gibt es nun zwei HMIs eine mit der ID “HMIID“ und die andere mit dem irreführendem Namen “wLanServerID“. Der WLanServer vertritt die Remote­HMI im InCarMultimedia­Framework. Über eine Socketverbindung ist der HP­iPAQ an das InCarMultimedia­Framework angeschlossen. Da die Remote­HMI als High­Level­Komponente fungieren soll, schickt sie die Befehle als 42
Application­Messsages an das Framework. Der WLanServer leitet diese Nachrichten an den MainDispatcher weiter, der dann über das Ziel der Nachricht entscheidet. Alle Nachrichten, die an die Remote­HMI versendet werden sollen, müssen als ReceiverID die “wLanServerID“ eingetragen haben. Alle Nachrichten, die der HP­iPAQ versendet sind mit “wLanServerID" im Absender markiert.
3.2.7 UpdateEvents und DatenContainer
Auf Target­Seite macht es Sinn, einen Datencontainer anzulegen und darin alle Daten zu halten. Die HMI zeigt bei einem UpdateEvent die neuen Daten an und ist somit auf dem neusten Stand. Außerdem kann man einen MOST­Parser aus dem MOST­Katalog generieren lassen, der den Datencontainer automatisch füllt siehe [WiTr­2005]. Die Remote­HMI kann nicht auf den Datencontainer zugreifen, da der Datencontainer im SharedMemory auf der Target­Seite liegt. Bei jedem Update­Event den DatenContainer zu streamen wäre nicht sehr sinnvoll, wenn man bedenkt, dass z.B. auf den Apple­iPod mehrere tausend Lieder passen und der DatenContainer, der zu allen Liedern Title, Spiellänge usw. speichert, riesig wird.
Will der iPod lediglich mitteilen, dass sich der aktuelle Track geändert hat, müsste man ein Update­Event verschicken und den kompletten DatenContainer streamen.
Oder man präzisiert das UpdateEvent und teilt der HMI mit, dass sich der aktuelle Track geändert hat, indem man als Opcode aktTrack und als Parameter1 UPDATE versendet.
Jetzt wäre es möglich, nur den Teil des Datencontainers zu übertragen, der wirklich benötigt wird.
Schauen wir uns einmal an, was nach Eintreffen eines UpdateEvent zu tun ist.
Die Remote­HMI bekommt ein UpdateEvent, kann aber nichts damit anfangen, weil sie keinen Zugriff auf den Datencontainer hat. Die WLanServer­Komponente, die die Remote­
HMI auf Target­Seite „vertritt“, hätte Zugriff auf den Datencontainer. Die Remote­HMI muss also der WLanServer­Komponente mitteilen, dass sie Teile des Datencontainers streamen soll.
Bisher war die WLanServer­Komponente nur dafür da, Nachrichten, die in ihrer Queue 43
angekommen sind, über Socket an den HP­iPAQ weiter zu leiten und die Nachrichten, die vom iPAQ kamen, in die Queue des MainDispatchers zu legen. Jetzt müsste die WLanServer­
Komponente jede Nachricht anschauen um eine eventuelle Anfrage fürs Streamen des DatenContainers nicht zu verpassen.
Aus Performance Gründen ist aber hiervon abzusehen. Erst müsste ein UpdateEvent an die Remote­HMI verschickt werden und danach müsste die Remote­HMI zurück senden, dass sie Teile vom DatenContainer benötigt, und danach würde erst der benötigte Wert eintreffen. Besser ist es in der Update­Nachricht den aktuellen Wert unterzubringen. Somit könnte man die WLanServer­Komponente einfach halten und eine hohe Performance erzielen.
Das High­Level­Event würde z.B. so aussehen:
Sender und ReceiverID wie gewohnt. Opcode VOLUME Parameter1 UPDATE, Parameter2 78 (aktuelleLautstärke).
Die Nachricht zum Ändern der Lautstärke hat als Opcode VOLUME als Parameter1 INC,DEC,oder SET und als Parameter2 im Falle eines INC's und DEC's die Anzahl der Schritte und im Falle von SET den absoluten Wert. Man erkennt hier eine gewisse Ähnlichkeit, die dem Programmierer der HMI eine leichte Handhabung mit den Devices garantiert. Bei größeren Datenmengen wird man dennoch nicht um das Streamen von Daten herum kommen, da in einer Update­Nachricht nicht genügend Platz ist, um beispielsweise die komplette Track­Liste des iPods zu übertragen. Da sich weder die Track­Liste des iPods noch die Track­Liste einer CD ständig ändern, sind hier Geschwindigkeitseinbußen unkritisch. Eine andere Möglichkeit wäre es, MOST­Nachrichten von Abspielgeräten direkt an die Remote­HMI weiter zu leiten. Dafür müsste eine Remote­HMI MOST­Nachrichten verstehen können. 44
3.3 Remote­HMI als MOST­Device
Es bestünde die Möglichkeit, die Remote­HMI direkt als MOST­Device zu gestalten. Sie würde dann anstelle der High­Level­Events über das MOST­Protokoll kommunizieren. An dieser Stelle ist es sinnvoll darüber nachzudenken, warum die lokale HMI mit High­Level­
Events kommuniziert.
Was waren die Gründe dafür, dass man dieses zusätzliche Protokoll eingeführt hatte?
Die High­Level­Events entsprechen den Bedientasten. Falls ein CD­Player den Befehl Scan nicht kennt, soll dieser trotzdem als High­Level­Event an die CD­Player­Komponente verschickt werden können. Die Komponente ist dann dafür zuständig, dass sie das High­
Level­Event Scan in mehrere MOST­Nachrichten verwandelt und somit das Scan nachbildet. Die Umsetzung eines Scans könnte wie folgt aussehen.
Play ( 10 sekunden warten ) ­> NextTrack ­> ( 10 sekunden warten ), ....
vergleiche [WiTr­2005].
Für den HMI­Programmierer ist es ebenfalls eine wesentliche Erleichterung, wenn er alle Geräte mit den gleichen High­Level­Events ansprechen kann, ohne darauf achten zu müssen, ob die Geräte die Befehle überhaupt kennen.
Falls man die Remote­HMI direkt als MOST­Device ansprechen wollte, dann würde man sicher auf Remote­HMI Seite den gleichen Weg gehen, den man im Framework auf Target­
Seite gegangen ist. Die Motivation wäre dabei auch die selbe. Man würde eine Abstraktionsschicht nach der anderen einführen um mehr und mehr zu vereinheitlichen, oder besser gesagt zu abstrahieren. Die MOST­Proxies würden wahrscheinlich wieder zum Dekodieren der MOST­Nachrichten verwendet werden. Die MOST­Proxies bieten nach oben ein einheitliche Schnittstelle, obwohl sie auf MOST Seite unterschiedliche Nachrichten versenden. Das Logische­Device ist dazu verpflichtet, fehlende Befehle mit einer Folge an niedrigeren Befehlen nachzubilden.
Das Scan und andere ähnliche Befehle werden wieder mit einer Folge von grundlegenden Befehlen nachempfunden. Das Logische­Device wäre dann eine Abstaktionsschicht über den Proxies. Das Konzept sieht vor, diese Abstraktionsschritte zu den Bedientasten hin, die ohnehin im Framework schon geschehen, nicht noch einmal neu auf Remote­HMI Seite zu implementieren, sondern gleich in Form von High­Level­Events mit der Remote­HMI zu kommunizieren.
45
3.4 AudioMaster
Der neu eingeführte AudioMaster soll zum einen die Ressourcen verwalten und zum anderen soll er es leicht ermöglichen, Geräte zu verbinden und zu trennen. Jedes Abspielgerät meldet sich beim AudioMaster an mit dem Opcode REGISER_SOURCE und den Channels, die es verwendet. So ist eine Erweiterung mit neuen Geräten sehr einfach und es ist nicht nötig, dass der Quellcode des AudioMasters beim Hinzufügen eines neuen Gerätes geändert werden muss. Jede HMI und jeder Verstärker registriert sich ebenfalls beim AudioMaster. Für die Verstärker ist der Opcode REGISTER_DESTINATION vorgesehen. Eine Erweiterung um eine beliebige Anzahl von Verstärkern ist so lange möglich, bis die Registrierungsliste der Verstärker voll ist. Gleiches gilt für die HMIs und die Abspielgeräte, die im folgenden Source­Devices genannt werden. Theoretisch soll es auch ermöglicht werden, dass sich eine Komponente anmeldet, die beispielsweise Audio­Daten auf Festplatte aufnimmt. Sie würde ebenfalls den Opcode REGISTER_DESTINATION verwenden. Ein Festplatten­Recorder soll sich dann auf die gleiche Weise mit einem Abspielgerät wie CD­
Spieler oder Radio verbinden lassen; genauso wie ein normaler Verstärker. Der AudioMaster kommuniziert auch auf High­Level Ebene genau wie die HMIs. Zum Verbinden von Quellen und Senken ist es für die HMI nicht nötig zu wissen, um welche Channels es sich hierbei handelt. Um ein Abspielgerät mit einem Verstärker zu verbinden, schickt eine HMI eine ApplicationMessage mit dem Opcode CONNECT und als Parameter die Komnponenten­IDs der beiden zu verbindenden Geräte an den AudioMaster. Dieser entscheidet dann, ob die Verbindung zustande kommt und wer die Kontrollrechte über die angeforderten Geräte bekommt. Falls eine Verbindung hergestellt werden soll, schickt der AudioMaster dem Verstärker eine Nachricht mit den Quellen, auf die sich die Senken des Verstärkers verbinden sollen. Der Verstärker muss also auch nicht wissen, welche Abspielgeräte vorhanden sind, damit ist das Erweitern des Framworks vergleichsweise einfach geworden. Im bisherigen Framework veranlasste man den Verstärker, sich mit dem Tuner zu verbinden, hierzu war es aber nötig, dass der Verstärker den Tuner kannte, und dass er wusste, welche Kanäle er benutze. Der AudioMaster versendet GOT_CONTROL und LOST_CONTROL Nachrichten an die HMIs, damit diese jeweils wissen, ob sie eine 46
Steuerberechtigung über Abspielgeräte und Verstärker besitzen oder nicht und gegebenenfalls Funktionalitäten und Buttons ausblenden können. Wenn eine HMI mit hoher Priorität den Tuner mit Amp0 verbunden hat, kann eine andere HMI mit niedrigerer Priorität den Tuner mit einem anderen Verstärker verbinden. In diesem Falle würden beide Verbindungen vom AudioMaster genehmigt werden und die HMI mit höhrer Priorität würde die Steuerberechtigung für den Tuner und den Amp0 bekommen. Die HMI mit niedrigerer Priorität bekommt nur Steuerbefugnis über Amp1, der für den Kopfhörerausgang zuständig sein soll. Das Verstellen der Sender soll in diesem Fall für die HMI mit niedrigerer Priorität ausgeblendet werden.
Abbildung 10: GOT_CONTROL
Abbildung 9: LOST_CONTROL
Wie in Abb. 9 zu sehen, bekommt die Remote­HMI nur die Steuererlaubnis für den Verstärker. Wechselt die HMI mit höherer Priorität in das CD­Menü, so versendet der AudioMaster ein GOT_CONTROL mit Parameter TunerID an die HMI mit niedrigerer Priorität, da sie nun die einzige HMI ist, die den Tuner steuern möchte (siehe Abb. 10 ). Der AudioMaster vermerkt sich alle bestehenden Verbindungen in einer Registry und verteilt die Steuerberechtigungen anhand der Priorität der HMIs. An einem kleinen Szenario wird gezeigt, was der AudioMaster leisten soll. Abbildung 11 visualisiert dieses Szenario mit einem Sequenzdiagramm.
47
3.4.1 Szenario
Nach dem Start des Frameworks reservieren sich alle Abspielgeräte wie bereits erwähnt synchrone Kanäle auf dem MOST­Bus. Sie melden sich beim AudioMaster an und teilen bei der Anmeldung ihre reservierten Kanalnummern mit. Die Verstärker (Amp1 und Amp2) melden sich auf die gleiche Weise beim AudioMaster an. Die lokale HMI meldet sich ebenfalls gleich nach dem Starten des Frameworks beim AudioMaster. Dieser vermerkt sich die angemeldeten Geräte in jeweils einer Liste für HMI's, Source­ und Destination­Devices. Die im Sequenzdiagramm mit HMI 2 betitelte HMI ist eine Remote­HMI, die eine niedrigere Priorität als die lokale HMI (HMI 1) besitzt. Sie meldet sich erst beim AudioMaster an, sobald eine Verbindung besteht (siehe Abb. 11 ). Der Fahrer des Autos hat das Tuner­Menü ausgewählt. Die HMI­Komponente sendet darauf hin einen Verbindungswunsch von Tuner und Amplifier1 an den AudioMaster. Da weder der Tuner noch der Verstärker benutzt werden, wird diesem Verbindungswunsch nachgekommen und eine Verbindung veranlasst. Hierzu sendet der AudioMaster dem Verstärker, mit welchen Kanälen er sich verbinden soll. Der Verstärker weiß nicht, um welches Abspielgerät es sich hierbei handelt. Um eine dynamische Erweiterbarkeit zu gewährleisten, ist es nötig das Konzept so zu gestalten, dass die Komponenten nichts voneinander wissen müssen, sondern jeweils nur den AudioMaster ansprechen. Der AudioMaster bestätigt den Verbindungswunsch; die beiden darauf folgenden Nachrichten teilen der HMI mit, dass sie die Kontrolle über den „Tuner“ und den „Amp1“ bekommen hat.
Das Kind auf dem Rücksitz fühlt sich durch die ständigen Staumeldungen und Nachrichten des gerade ausgewähltem Senders gelangweilt. Es nimmt sich den iPAQ und die Kopfhörer und beschließt, einige Lieder des iPods, der vorn im Auto angeschlossen ist, zu hören. Die HMI 2 (iPAQ) versendet einen Verbindungswunsch von iPod und Amp2; da beide Geräte unbenutzt sind, kommt der AudioMaster auch diesem Verbindungswunsch nach. Der AudioMaster vermerkt sich in einer Registry die gerade aktuellen Verbindungen. Hier ist jetzt die Verbindung HMI1­Tuner­Amp1 und die Verbindung HMI2­iPod­Amp2 hinterlegt. Zu jedem Source­ und Destination­Device vermerkt sich der AudioMaster die steuerberechtigte HMI. 48
Die HMI 1 ist momentan über den Tuner und den Amp1 steuerberechtigt. Die HMI 2 darf den iPod und den zweiten Verstärker steuern.
Da das nächste Lied im Radio nicht nach dem Geschmack des Fahrers ist, beschließt dieser auch einige Lieder des iPod's zu hören. Wieder wird ein Verbindungswunsch an den AudioMaster versandt. Dieser veranlasst den Amp1 dazu, sich nun auch auf die Kanäle 4,5,6 und 7 zu verbinden.
Nun wird anhand der unterschiedlichen Prioritäten entschieden, dass die HMI1 die Kontrolle bekommen soll. Deshalb wird der HMI2 die Kontrolle über den iPod entzogen. Die Kontrolle des zweiten Verstärkers bleibt aber bei der zweiten HMI. Das Kind auf dem Rücksitz ist immer noch in der Lage über die gewünschte Lautstärke der Kopfhörer selbst zu entscheiden. Die Kontrolle über den iPod hat nun HMI1. Der Fahrer des Autos (Bediener der HMI1) bestimmt, welches Lied gespielt wird, er entscheidet auch darüber, wie laut die Musik im Wagen gespielt wird, da er die Kontrolle über den iPod und den ersten Verstärker besitzt. Das Kind hinten schaltet den iPAQ aus, da die Soundanlage im Wagen einen klareren Klang als die kleinen Kopfhörer erzeugen und ohnehin die gleiche Musik spielt. Die HMI2 meldet sich mit UNREGISTER_HMI ab. Der AudioMaster trägt die HMI2 aus seiner HMI­Liste aus. Danach durchsucht er die Registry nach Einträgen, die die zweite HMI betreffen. Die Verbindung HMI2­iPod­Amp2 wird aus der Registry gelöscht. Da nun in der Registry keine Verbindung mehr zu dem zweiten Verstärker besteht, veranlasst der AudioMaster den Amp2 dazu sich von den Kanälen zu trennen.
Der Beifahrer möchte sich den iPod näher ansehen und zieht ihn dazu aus der Halterung. Die iPod­Komponente registriert dies und meldet sich mit UNREGISTER_SOURCE ab.
Der AudioMaster teilt die verlorene Verbindung der HMI mit, veranlasst den Verstärker sich von den Kanälen 4,5,6 und 7 zu trennen und schickt der HMI Nachrichten, dass sie die Kontrolle über den Verstärker und auch den iPod verloren hat. Die Registry des AudioMasters ist nun leer. Es sind keine Geräte mehr verbunden.
49
Tuner
iPod
HMI 1
HMI 2
AudioMaster
Amp 1
Amp 2
REGISTER_DESTINATION
REGISTER_SOURCE 0,1,2,3
REGISTER_SOURCE 4,5,6,7
REGISTER_DESTINATION
REGISTER_HMI
REGISTER_HMI
CONNECT Tuner, Amp1
CONNECT 0,1,2,3
CONNECT OK
GOT_CONTROL Tuner
GOT_CONTROL Amp1
CONNECT iPod, Amp2
CONNECT 4,5,6,7
CONNECT OK
GOT_CONTROL iPod
GOT_CONTROL Amp2
CONNECT iPod, Amp1
CONNECT 4,5,6,7
CONNECT OK
LOST_CONTROL iPod
GOT_CONTROL iPod
UNREGISTER_HMI
DISCONNECT
UNREGISTER_SOURCE
DISCONNECT
LOST_CONNECTION iPod, Amp1
LOST_CONTROL iPod
LOST_CONTROL Amp1
Abbildung 11: Interaktion mit dem AudioMaster (Sequenzdiagramm)
50
3.4.2 Prioritätsvergabe
Im Moment bekommt eine HMI, wenn sie sich beim AudioMaster anmeldet, anhand ihrer Komponenten­ID von ihm eine Priorität zugewiesen. Dies setzt voraus, dass der AudioMaster die HMI kennt. Möchte man also eine weitere HMI hinzufügen, ist eine Änderung im AudioMaster nötig. Eine weitere Möglichkeit besteht darin, die HMIs und ihre zugehörigen Prioritäten in einer Konfigurationsdatei abzulegen, die der AudioMaster bei jedem Start einliest, hierdurch kann eine Änderung des Codes vermieden werden. Eine dritte Möglichkeit wäre, dass die HMI ihre Priorität dem AudioMaster beim Anmelden mitteilt, so muss weder eine Konfigurationsdatei noch der Quellcode des AudioMasters verändert werden, falls eine HMI hinzugefügt wird. Diese Möglichkeit setzt aber voraus, dass die Programmierer der GUIs sich nicht in den Prioritäten übertrumpfen möchten sondern kooperativ programmieren und jeder eine sinnvolle Priorität einstellt. Die Anmeldung würde dann wie folgt aussehen: Eine HMI registriert sich beim AudioMaster mit dem Opcode REGISTER_HMI und der Priorität als Parameter. Das ganze Projekt ist ohnehin so ausgelegt, dass die Programmierer sich kooperativ verhalten müssen, deshalb ist es auch unproblematisch, dass sie die Priorität einstellen können. Wenn die Programmierer eine höhere Priorität erlangen möchten, wäre es auch bei den anderen beiden Verfahren möglich, indem sie einfach den Absender fälschten. Eine noch einfachere Möglichkeit an die Steuerberechtigung zu kommen ist, einfach die LOST_CONTROL Nachrichten zu ignorieren.
51
4 Eine einheitliche Grafik für alle Geräte
Wie in der Einleitung bereits erwähnt, beschäftigt sich diese Arbeit mit der remote Steuerung des InCarMultimedia­Systems und der dazu nötigen Konzepte. Es wäre praktisch, wenn man für die Remote­Geräte und die InCarMultimedia­Systeme eine einheitliche Grafik verwenden könnte, aber dies ist aus einigen Gründen nur schwer realisierbar. Was möglich und was eher unrealistisch ist, wird anhand verschiedener Betrachtungen auf den nächsten Seiten erörtert.
4.1 Display
Hierzu betrachten wir zuerst die Display­Größen der unterschiedlichen HMIs. Nachfolgende Grafik zeigt die Displaygrößen der verwendeten Geräte in Pixel an.
Abbildung 12: Display­Sizes
Wenn man eine einheitliche Grafik für alle Geräte erzeugen möchte, könnte man auf die Idee kommen, die Breite und Höhe der einzelnen Grafikelemente nicht in absoluten Pixeln sondern in Prozent zur Displaygröße anzugeben. Target NG3 mit einer Display­Höhe von 52
480 Pixeln müsste laut Pixelverhältnis fünf mal so hoch sein, wie Target PON mit einer Display­Höhe von 96 Pixeln. Misst man die Höhe der Displays hingegen in cm wird man feststellen, dass der tatsächliche Höhenunterschied nicht einmal das Dreifache beträgt. Dies ergibt sich dadurch, dass die Pixelgröße und der Abstand der Pixel bei beiden Targets unterschiedlich sind. Eine prozentuale Umrechnung wird hierdurch erschwert. Das größere Problem bei einer prozentualen Umrechnung ist, dass das Seitenverhältnis der beiden Displays zu unterschiedlich ist und eine prozentuale Umrechnung zu einer sehr starken Verzerrung führen würde. Beim HP­iPAQ ist das Display höher als breit, da es möglich ist, diesen zu drehen, erhält man auf diese Weise ein ähnliches Seitenverhältnis, wie das des Targets NG3. Hier wäre eine gemeinsame grafische Oberfläche denkbar. Mobiltelefone gibt es mit den verschiedensten Displaygrößen, die meisten aber sind höher als breit. Ein Drehen kommt meist nicht in Frage, da das Bedienen der Tasten erschwert würde. Die Schriftgröße muss bei allen Targets spezifisch ausgewählt werden, sie muss gut leserlich sein. Eine gemeinsame Grafik setzt voraus, dass ein paar “Defines“ eingeführt werden, so wird auf die einzelnen Gegebenheiten der unterschiedlichen Displays eingegangen. Man könnte z.B. beim Target PON, welches eine sehr geringe Displayhöhe aufweist, im CD­Menü drei Lied­Titel untereinander anzeigen lassen und im Target NG3 fünf oder sechs Lied­Titel. Beim Siemens S65, das ein längliches Display besitzt, könnte man die Liednamen kürzen, um so Darstellungsbreite einzusparen. Prinzipiell wäre eine gemeinsame Grafik machbar.
4.2 Hardware / Software
Eine gemeinsame grafische Oberfläche setzt voraus, dass die Targets dies in Software und Hardware unterstützen. Zur Zeit ist die Vielzahl der Handys nicht in der Lage, z.B. OpenGL einzusetzen. Dies liegt an der meist sehr eingeschränkten Hardware, die sich aber rasant entwickelt. Mittlerweile unterstützen einige Handys bereits 3D Funktionalitäten. Auf dem Target „PON“ wird eine Photon Grafik benutzt, die auf der GF­Lib aufsetzt. Die GF­Lib ist QNX's Grafik Framework, diese Library ist auf den Handys ebenfalls nicht vorhanden. Beim neueren NG3 Target setzt man auf OpenGL ES. 53
Photon microGUI
(including
io-graphics, etc.
Graphics
Framework
library
(GF)
OpenGL ES
application
Custom GUI
Third-party
2D library
GF
OpenGL
ES
GF
io-display
monitor process
devg-*.so
devg-*.so
devg-*.so
devg-*.so
Hardware
Abbildung 13: QNX's Grafik Abstraktionen angelehnt an [qnx­2006]
OpenGL ES ist eine abgespeckte Version von OpenGL, die für die Verwendung in embedded Bereichen abgestimmt wurde. OpenGL ist weitestgehend abwärtskompatibel, so dass man mit OpenGL ES erstellte Grafiken mit kleinen Änderungen auch unter OpenGL laufen lassen kann. Durch Abstraktionsschichten wäre es möglich, eine gemeinsame Basis zu finden, auf der alle aufsetzen. In der Regel möchte man aber die Grafik des neuen Targets ausreizen, ohne sich durch die Kompatibilität mit einem älteren Grafik­Chip einschränken zu lassen.
54
4.3 Hard­ und Softkeys
Für eine gemeinsame HMI ist nicht nur die Anzeige wichtig, sondern vor allem die Steuerung. Der MiniCommander (kurz MiniCom) ist das Eingabegerät des Target PON. Er verfügt neben einem Dreh­Rad über sechs unbeschriftete Tasten, die als Softkeys in der Grafik abgebildet werden. Abbildung 15: MainMenu
Abbildung 14: MiniCom
Abbildung 16: TunerMenu
Mit dem MiniCom ist es möglich, aus dem Hauptmenü in maximal sechs Untermenüs zu gelangen (von langen Tastendrücken etc. abgesehen). Beim Eingabegerät des Target NG3 (MaxiCommander) gibt es für den Wechsel in die Untermenüs Hardkeys, so fallen diese in der Grafik sinnvollerweise weg. Der Wechsel von Radio zu Tuner kann auf direktem Weg stattfinden und nicht über den Umweg über das Hauptmenü, wie es im Target PON realisiert wurde. Der HP­iPAQ besitzt außer dem Stift zum Steuern vier weitere Tasten, die man als Softkeys einsetzen könnte. Da der HP­iPAQ aber auch über einen Stift verfügt, kann man diesen dazu benutzen, beliebig viele Softkeys auf dem Display zu wählen. Neben dem Nummernfeld besitzen Handys meist auch Softkeys und Joystick. Durch die verschiedensten Hard­ und Softkeys der unterschiedlichen Geräte ergibt sich ein anderer Menübaum und so gibt es z.B. im Target NG3 kein Hauptmenü. Auf dem PC sieht das alles etwas anders aus. Man kann das Framework in einem Fenster anzeigen lassen, das die identische Größe des entsprechenden Targets besitzt. Zusätzlich zeigt man in einem anderen Fenster einen Simulator, der die Steuereinheit ersetzt.
55
Folgende Abbildungen zeigen Simulatoren für die QNX­x86 Plattform.
Abbildung 17: MiniCom­Simulator
Abbildung 18: MaxiCom­Simulator
Für eine Simulation am PC ist es auch möglich, die Tastendrücke der Eingabegeräte über Sockets zu streamen. Zur Not könnte man auch die Tastatur als Hardkeys verwenden, indem man logische Zuordnungen sucht, die Taste „R“ für Radio oder „T“ für Tuner, mit der Maus könnte man Softkeys anklicken. Dies erfordert aber, dass die Widget dies unterstützen, deshalb müssten bei einem Simulator zusätzlich Mouse­Events bearbeiten werden. Möchte man den HP­iPAQ nur zur Anzeige verwenden und nicht zum Steuern, ist hier auch eine gemeinsame Grafik denkbar. Ein Simulator, um die Hardkeys in einem zweiten Fenster abzubilden, ist aus Platzmangel auf dem HP­iPAQ oder einem Handy nicht sinnvoll.
Eine gemeinsame Grafik für ein Target und den PC ist für Simulationszwecke sinnvoll und auch machbar. Für alle Targets hingegen eine gemeinsame Grafik zu erzeugen, ist nicht sehr sinnvoll, da die Eingabemethoden und auch die Displays zu unterschiedlich sind. Außerdem würde man sich am Target mit den geringsten Leistungen orientieren müssen.
56
5 Entwicklung einer HMI für den HP­iPAQ h5500
Da der Entschluss getroffen wurde, keine gemeinsame Grafik zu erzeugen, ist es nötig, für die einzelnen Remote­Geräte zu erörtern, auf welches Betriebssystem und welchen Grafik­
Libraries aufgesetzt werden soll. Das Betriebssystem und dessen mitgelieferten Hardwaretreibern entscheiden ebenfalls darüber, welche Techniken der Kommunikation möglich sind.
5.1 Betriebssysteme für PDAs
Für PDAs gibt es die verschiedensten Betriebssysteme wie z.B. Palm Os, Pocket PC, Linux, OpenBSD, Windows CE, NewtonOS und viele mehr. Einige davon laufen nur auf bestimmten PDAs, da sie nur eine Prozessor­Architektur unterstützen und fallen deshalb schon aus der Wahl. Die Wahl des Betriebssystems fiel auf Linux; es ist kostenlos, der Quellcode frei verfügbar und hält sich sehr nahe am Posix Standard. Das war ein wichtiges Entscheidungskriterium.
5.1.1 Distribution
Linux gibt es in den verschiedensten Distributionen, sie bestehen aus dem Kernel und aus einer Zusammenstellung von Software, die mitgeliefert wird. Die Bequemlichkeit der Nutzer ist oft ausschlaggebend für die Wahl der Distribution, so entscheiden oft die Standard Oberfläche und der verwendete Paket­Manager darüber, welche Distribution gewählt wird. Theoretisch könnte man nahezu jede Distribution seinen Wünschen anpassen, da Linux Open­Source­Software ist und demnach der Quellcode offen liegt. In unserem Fall sieht das Ganze etwas anders aus. Für den HP­iPAQ ist eine sehr kleine Linux Distribution erforderlich, Desktop­Umgebung wie KDE oder GNOME wären ebenfalls zu anspruchsvoll für die Hardware.
Die Wahl der Distribution fiel auf Familiar, denn diese Distribution wurde speziell für den HP­iPAQ entwickelt, und ist vom Resourcenbedarf sparsam gehalten. Die Distribution ist nicht nur auf den iPAQ beschränkt, sie ist ebenso auf dem Siemens Simpad und dem Sharp 57
Zaurus lauffähig. Als Paket­Manager wird Ipkg eingesetzt. Dieser ermöglicht es, unser Remote­Projekt in einer späteren Version als Paket auszuliefern. Ein SSH­Server ist ebenfalls in die Distribution integriert. Er ermöglicht es, den iPAQ aus der Ferne zu konfigurieren. Konfigurationsdateien können über SSH und einen Texteditor wie vi mit einer Tastatur bearbeitet werden. Wie bei Desktop­Distributionen gibt es für Familiar unterschiedliche Grafik Aufsätze.
5.2 Grafik für Linux PDA's
Wichtig für einen PDA ist, dass für die gewählte Oberfläche PIM­Applikationen vorhanden sind, denn man möchte mit seinem PDA nicht nur das InCarMultimedia Framework remote steuern können, sondern seinen PDA wie mit der vorherigen Software auch für Terminplanung, Kontaktverwaltung etc. nutzen können. Bei der Wahl der Oberfläche gilt es deshalb darauf zu achten, dass es umfangreiche Standard­Software für diese Oberfläche gibt.
5.2.1 QTE / Qt­Embedded
Qt­Embedded ist die Embedded Version von Qt. Qt ist ein Grafik Framework, mit dem z.B. KDE programmiert wurde. Qt­Embedded setzt direkt auf dem Linux Framebuffer auf, so ist es möglich X11 und Xlib, die bei Qt üblicherweise verwendet werden, zu vermeiden und Speicher, der auf embedded Geräten ohnehin knapp ist, zu sparen. Unter der Bedingung, dass man nur nichtkommerzielle Open­Source­Produkte entwickelt, ist Qt­Embedded kostenlos. Qt­Embdedded ist keine grafische Umgebung, sondern das unter einigen grafischen Oberflächen liegende Grafik­Framework.
58
5.2.2 Opie
Open Palmtop Integrated Environment
Opie wird von keiner speziellen Firma oder Organisation entwickelt oder vertrieben. Opie wird stattdessen von Software­Entwicklern entwickelt, die über die ganze Welt zerstreut sind und sich dem Entwickeln freier Software verschrieben haben, dem sogenannten Opie­
Team. Opie setzt auf Qt/embedded als Grafik Toolkit auf. Wenn man einen Vergleich zu den Desktop Rechnern zieht, könnte man Opie als kleinen Bruder von KDE bezeichnen, einige Entwickler von KDE sind auch zugleich Opie Entwickler.
5.2.3 OTopia / QPE Das Qt Palmtop Environment ist eine grafische Umgebung für Linux. Es ist speziell für Devices mit knappen Resourcen entwickelt, ähnlich der Microsoft Windows CE Oberfläche. QTopia läuft sowohl auf PDAs als auch auf einigen Linux­
Handys und kann auf weitere embedded Geräte portiert werden. QTopia setzt auf Qt/Embedded auf, vergleichbar wie KDE Qt verwendet. QTopia wird genau wie Qt von der norwegischen Firma Trolltech entwickelt. Als Standardsoftware sind etliche Tools enthalten, darunter nicht nur PIM­
Applikationen sondern auch Player für Video und Abbildung 19: QTopia PDA Edition
(aus [lugod­2006])
Musik­Dateien.
59
5.2.4 GPE GPE (GPE Palmtop Environment) ist ebenfalls eine freie grafische Umgebung für PDAs. GPE nutzt das X Window System und das GTK+ Widget Toolkit. Damit ist es der Desktop­Umgebung GNOME sehr ähnlich; viele Programme für Linux können leicht portiert werden. Anpassungsarbeiten sind aber trotzdem nötig, da die meisten Programme nicht für eine so geringe Auflösung gedacht waren, wie sie die PDAs haben.
Abbildung 20: GPE (aus [Hand­2006])
5.2.5 GTK+ vs. Qt­Embedded
Aus den zuvor genannten Gründen wird Linux verwendet. Die Distribution Familiar zu verwenden ist sinnvoll, da sie speziell für dieses Endgerät entwickelt wurde. Bei der Wahl der grafischen Aufsätze ist das darunter liegende Grafik­Framework entscheidend. Es wird also nicht zwischen QTopia, OPIE oder GPE entschieden, sondern zwischen Qt­
Embedded und GTK+.
Die Distribution Familiar wird wahlweise mit OPIE oder GPE ausgeliefert, so ist die Verwendung von Qt­Embedded als auch GTK+ ohne größere Änderungen der Software möglich.
Die Wahl fiel bei der Grafik auf OPIE, da OPIE auf Qt/Embedded basiert. Qt/Embedded ist mit seinem Signal­Slot­Prinzip für den Programmierer eine gute Wahl, außerdem ist es auf verschiedenen Plattformen lauffähig. Der Hauptgrund für den Einsatz von Qt liegt darin, dass es unter einem dualen Lizenssystem verfügbar ist. Unter dem dualen Lizenz­System ist die Entwicklung von nichtkommerzieller Open­Source­Software kostenlos, das macht sich das Remote­Projekt zunutze. Es ist aber auch möglich für Firmen, die ihren Quellcode in aller Regel nicht offenlegen wollen, kommerzielle Software damit zu entwickeln. Sie sind dann verpflichtet, kommerzielle Lizenzen zu erwerben.
60
5.3 Ein neues Betriebssystem auf den PDA spielen
Auf der Seite http://Handhelds.org findet man HowTo's, die beschreiben, wie man den Bootloader und anschließend die Distribution Familiar aufspielt. Bevor man dies tut, sollte man darauf achten, dass die neuste Firmware für das WLan­Modul bereits installiert ist, da dieses Firmware Update nur für das original Betriebssystem vorhanden ist. Auf der oben genannten Internet­Seite stehen sowohl der Bootloader als auch die Linux Distribution Familiar zum Download bereit. Der aktuelle Bootloader unterstützt das LC­
Display des h5500 nicht, daher bleibt das LC­Display nach dem Einschalten des Gerätes erst einmal dunkel.
5.4 Qt/Qt­Embedded
Eine Errungenschaft von Qt ist sein Meta­Object­Mechanismus, der zu Objekten Lauzeittypinformationen und Vererbungsinformationen etc. hinzufügt. Zu diesen Errungenschaften gehört auch der Signal/Slot­Mechanismus, der im Folgenden kurz beleuchtet wird. Ebenso wird kurz auf die Programme eingegangen, die für die Programmierung mit Qt nötig sind. 61
5.4.1 Signal­Slot
Eine Grundlage für Qt ist das Signal­Slot Konzept, es ermöglicht Objekte zu verbinden, ohne dass sie voneinander wissen müssen. Slots sind im Grunde normale Memberfunktionen von C++, sie können als privat, public oder protected deklariert werden. Sie können virtuell sein oder überladen werden. Man kann Signale mit Slots verbinden, dies ist zugleich für den Programmierer der einzige ersichtliche Unterschied zwischen Slots und normalen Memberfunktionen. Wenn ein Signal ausgesendet wird, werden alle Slots nacheinander abgearbeitet, die mit dem Signal verbunden wurden. Die Reihenfolge der Abarbeitung ist dabei willkürlich. Mit der Funktion connect, die Bestandteil von QObject ist, werden Signale mit Slots verbunden.
QObject::connect(Sender, SIGNAL(SignalName), Receiver, SLOT(SlotName));
Signale können auch untereinander verbunden werden. Eine Signal­Signal Verbindung bewirkt, dass mit dem ersten Signal automatisch auch das zweite Signal ausgesendet wird.
connect(ToggleButton1, SIGNAL(clicked()), this, SIGNAL(aktivated()));
Dies gilt aber nicht im umgekehrten Fall: Falls Signal2 ausgesendet wird, wird nicht automatisch auch das erste mit versendet.
Signal­Signal Verbindungen unterscheiden sich nicht von Signal­Slot Verbindungen.
Wenn das Signal ausgesendet wird, wird nicht nur das mit ihm verbundene andere Signal ausgeführt, sondern auch die mit beiden Signalen verbundenen Slots.
Mit disconnect können Signal­Slot oder Signal­Signal Verbindungen zur Laufzeit wieder getrennt werden. Der Aufruf sieht wie der connect(...)­Aufruf aus. Die Möglichkeit zur Laufzeit Verbindungen zu ändern wird im vorliegenden embedded GUI­
Kontext kaum benötigt.
Falls Objekte gelöscht werden, die noch mit Signalen verbunden sind, kümmert sich Qt 62
selbstständig um das vorherige Trennen.
Bei Verbindungen zwischen Signalen und Slots ist zu beachten, dass Parametergleichheit besteht.
Die Parameter müssen den gleichen Typ und die gleiche Reihenfolge haben. Bei Signalen, die mehr Parameter haben als der Slot, werden die letzten Parameter ignoriert.
Was Signale im einzelnen sind, wird selbst in der Online­Dokumentation nicht erläutert.
Signale erinnern sehr stark an Funktionsaufrufe. Um ein Signal auszusenden, ist es nur nötig, den Befehl emit und den Signalnamen incl. Parameter abzusetzen.
Bsp.: emit AppMessage(mComponentID,VOLUME,INC,5,0);
Der Meta­Object­Compiler generiert für Signale Funktionen mit den gleichen Parametern. An den Stellen, an denen Signale ausgesendet werden, werden diese durch Funktionsaufrufe ersetzt. Das Schlüsselwort emit fällt dadurch weg. Übrig bleibt ganz normaler C++ Code, dadurch ist jeder C++ Compiler für das Signal­Slot Prinzip geeignet. Für das Signal AppMessage wird folgende Funktion erzeugt.
void Amplifier::AppMessage( int t0, int t1, int t2, int t3, int t4 )
für dessen Implementierung werden weitere Headerdateien „qobjectdefs.h“ und „qsignalslotimp.h“ herangezogen. Diese Funktion arbeitetet die Liste mit verbundenen Slots ab. Das Signal­Slot­Prinzip, wie es in Qt verwendet wird, ist eine synchrone Kommunikation, die an Prozessgrenzen gebunden ist.
63
5.5 Designer
Der Qt­Designer hilft beim schnellen Entwickeln von GUIs. Mit dem sogenannten
Drop“­Mechanismus
„Drag
'n werden Grafikelemente platziert und Signale mit dazugehörigen Slots verbunden. Das Einbinden eigener Widgets wird ebenfalls unterstützt. Der Qt­Designer bietet verschiede Layouts an, damit die GUI auch bei Größenänderungen noch harmonisch wirkt. Die Grafikelemente können in Gitterform, horizontal oder vertikal angeordnet werden. Abbildung 21: Verbinden von Signalen mit Slots im Designer
Eine absolute Platzierung ist ebenfalls möglich. Sie passt sich aber den Größenänderungen nicht an. Für komplexere GUIs besteht die Möglichkeit mehrere dieser Layoutvarianten zu kombinieren. Um Signale mit Slots zu verbinden, zieht man mit gedrückter Maustaste eine Verbindung von dem Widget, welches das Signal versendet zu dem Widget, das den Slot bereitstellt (siehe Abb. 21). Daraufhin erscheint ein Fenster, das die Signale des einen Widgets und die Slots des anderen Widgets sowie Verbindungen der beiden Widgets anzeigt (siehe Abb. 22). Beim Verbinden von Signalen und Slots wird bereits die Parametergleichheit überprüft. Die GUIs die man mit dem Qt­
Designer erstellt hat, werden in UserInterface­Dateien abgelegt.
Abbildung 22: Signal­Slot Verbindungen
64
5.6 UIC ­ User­Interface­Compiler
Der User­Interface­Compiler von Qt erzeugt aus .ui­Dateien, wie sie vom Qt­Designer erstellt werden, C++­Quelldateien und dazugehörige Header. Die .ui­Dateien liegen im XML­Format vor und müssen erst gewandelt werden, bevor sie in den Kompiliervorgang integriert werden können.
5.7 MOC ­ Meta­Object­Compiler
Der Meta­Object­Compiler fügt Laufzeit Typinformationen, Vererbungs Informationen etc. zu den Klassen hinzu. Er ist auch dafür zuständig, dass die Signal und Slot Macros richtig umgesetzt werden. Aus der Datei „MyClass.cpp“ generiert er die Datei „moc_MyClass.cpp“, diese enthält statt der Macros den richtigen Quellcode, sie wird anstelle der vorherigen Datei im Kompiliervorgang verwendet. Im Normalfall wird der Meta Object Compiler nicht per Hand aufgerufen. In dem von QMAKE generierten Makefile sind die Aufrufe für den Meta Object Compiler bereits enthalten. 5.8 Qt­Assistant
Der Qt­Assistant ist eine Applikation, die bei der Dokumentation behilflich ist. Er enthält die Online­Dokumentation und ist daher für den Programmierer von großem Nutzen. Es gibt die Möglichkeit, ihn um die eigene Hilfe zu erweitern. An einer zentralen Stelle ist so die Hilfe von Qt und den eigenen Widgets abrufbar.
65
5.9 Remote HMI als High­Level­Komponente
Das Konzept sieht vor, die Remote HMI als High­Level­Komponente zu gestalten, damit Abstraktionsschritte nicht mehrmals vollzogen werden müssen. Gerade für eine Remote­HMI wie z.B. ein Mobiltelefon ist möglichst alles was auch auf dem InCarMultimedia­System geschehen kann, auch dort auszuführen, da dieses im Normalfall über mehr Rechenleistung verfügt, als ein Mobiltelefon. Aber viel wichtiger ist es, dass es hierdurch ermöglicht wird, Expertenwissen zu kapseln. Für die Entwicklung der Programmoberfläche sollten Funktionen auf einer höchstmöglichen Abstraktionsebene zur Verfügung stehen. Die untenliegenden Geräte und deren Kommunikationsprotokoll sollten für die Programmierung
unerheblich sein. Diese Vorgehensweise der Trennung einzelner Funktionsbereiche ist inzwischen selbst in der mit ca. 1000 Quelltextdateien relativ kompakten und übersichtlichen Hochschulsoftware nötig, um den Aufwand bei Erweiterungen und Änderungen möglichst niedrig zu halten. Ich sehe meine Aufgabe darin, die Remote HMI so zu gestalten, dass man so wenig wie möglich Gerätewissen mitbringen muss; so kommuniziert man mit High­Level­
Events, die in der nachfolgend erläuterten CMessage enthalten sind.
Die Nachrichten werden in unserem Framework als CMessage versendet. Diese CMessage Klasse besteht aus einem Union, das MostMessages und AppMessages vereint.
...
union msg {
AppMessage appMsg;
MostMessage mostMsg;
} theMessage;
...
Desweiteren gibt es in dieser Klasse Abbildung 23: Aufbau der CMessage
Setter­ und Getter­Methoden für den Zugriff auf sämtliche Daten. High­Level­Events werden in unserem Framework in sogenannten Application­Messages (AppMessage) versendet. Die Application­Messages bestehen in unserem Framework aus dem mType, dieser hilft bei der Feststellung, ob es sich um eine MOST­Nachricht oder ein High­Level­Event handelt. 66
Desweiteren besteht ein High­Level­Event aus der SenderID und ReceiverID, in der die KomponentenID des Absenders und des Empfängers stehen. Die KomponentenID's sind in der Global.h hinterlegt, somit ist es für das Remote HMI­Projekt nötig, dass die Global.h und die CMessage.h immer mit dem Framework auf gleichem Stand gehalten werden. Die Daten des High­Level­Events unterteilen sich in opcode und parameter1­4. Um die Lautstärke des Verstärkers zu ändern, ist es nur nötig die Funktion sendMessage des MainDispatchers aufzurufen und mit den richtigen Werten zu füllen.
CMainDispatcher::sendMessage(HMIID,VOLUME,Amp0ID,SET,10);
Auf Remote­Seite ist kein MainDispatcher vorhanden, deshalb erzeugt man eine CMessage, setzt die Werte über die Setter­Methoden der CMessage Klasse und versendet sie dann über Socket.
...
msg.setSenderID(HMIID);
msg.setReceiverID(Amp0ID);
msg.setOpcode(VOLUME);
...
Das High­Level­Protokoll ist sehr einfach gehalten und somit leicht erlernbar. Für den HP­
iPAQ wurde unter Qt ein Slot eingeführt, der das Setzen über Setter­Methoden erledigt und man so einen ähnlichen Aufruf wie bei der sendMessage­ Methode des MainDispatchers hat.
emit AppMessage(mComponentID,VOLUME,SET,Volume,0);
In diesem Fall ist mComponentID der Empfänger (Amp1ID). Da im Remote­HMI Projekt der Absender immer die Remote­HMI selbst ist, wird der Absender an anderer Stelle hinzugefügt. VOLUME und SET haben die gleiche Bedeutung wie oben, eben dass die Lautstärke gesetzt werden soll. In der Variablen Volume ist der Wert hinterlegt, der gesetzt werden soll. Die angefügte 0 ist also nicht der Wert, der gesetzt wird, wie man eigentlich vermuten könnte, sondern nur ein Lückenfüller, da der Slot aus Kompatibilität mit anderen Funktionen, die mehr Parameter benötigen, fünf Werte entgegennimmt. 67
5.9.1 Der DisableButton
Ein normaler QPushButton kennt die Slots setDisable(bool) und setEnable(bool), diese Funktionen arbeiten wie gewollt, jedoch ist die Anzeige des Buttons im deaktivierten Zustand nicht sehr attraktiv. Dies ist der Grund, einen eigenen Button zu entwickeln.
Der DisableButton wird von QPushButton abgeleitet und erhält zusätzlich die Slots _Disable(bool) und _Enable(bool). Er enthält zwei QPixmaps, von denen eins bei aktiviertem Zustand und das andere bei deaktiviertem Zustand angezeigt wird. Da die Original­Funktionen setDisable(bool) und setEnable(bool) nicht mehr verwendet werden, muss auf eine andere Weise verhindert werden, dass im deaktivierten Zustand das Signal „clicked“ gesendet wird. Dafür könnte man die Reaktion auf Mouse Events überschreiben oder man reagiert einfach nicht auf das Signal „clicked“, sondern auf ein neues Signal, welches mit großem Anfangsbuchstaben beginnt. Dieses neue Signal Clicked() wird nur dann ausgesendet, wenn das Signal clicked() gesendet wird und der Button enabled ist.
Um dies zu erreichen, wurde ein SLOT implementiert, der mit dem Signal clicked() verbunden wurde. Dieser prüft, ob der Button sich im aktivierten Zustand befindet, und sendet gegebenenfalls das Signal Clicked().
Das Verbinden des Signals clicked() mit dem HandleClicked()­Slot geschieht im Konstruktor der DisableButton Klasse, so wird sichergestellt, dass sich der Programmierer nicht mehr um das Verbinden kümmern muss. Bei dem neuen Widget DisableButton ist zu beachten, dass beide QPixmaps richtig initialisiert werden, da es zum Speicherfehler kommt, wenn das Widget ein QPixmap anzeigen will, das nicht vorhanden ist. Zum Initialisieren der QPixmaps gibt es die Slots initPic1(QPixmap*) und initPic2(QPixmap*). Diese können per Drag und Drop im Designer mit Slots der Klasse MyPic verbunden werden. 68
5.9.1.1 Die MyPic­Klasse
Die Klasse MyPic legt statische Bilder in Form eines CharakterArrays im CodeSegment ab. Die QPixmaps existieren so jeweils nur einmal und können von verschiedenen Widgets verwendet werden. Für jedes enthaltene Bild gibt es ein Signal, das ausgesendet wird, wenn man die Init­Funktion der Klasse MyPic aufruft. Dieses Signal enthält als Argument einen Zeiger auf QPixmap, genau wie es der initPicX()­SLOT von der Klasse DisableButton erwartet.
Was getan werden muss um ein neues Bild zur Klasse hinzuzufügen, sei hier kurz am Beispiel des Stop.png's erläutert.
In die Header­Datei wird ein neuer Zeiger auf ein QPixmap eingefügt. QPixmap *stop;
In der Sektion "signals:" ist es nötig, ein neues Signal zu deklarieren.
void pic_stop(QPixmap *);
Das Signal trägt den Namen pic_stop und versendet einen Zeiger auf ein Objekt des Typs Qpixmap. Um sicherzustellen, dass der Pointer auch auf das richtige Bild zeigt, sind weitere Modifikationen in der cpp­Datei der Klasse MyPic erforderlich.
In der MyPic.cpp wird ein Puffer angelegt, in dem das PNG Platz findet. Die Größe des benötigten Puffers wird mit Hilfe eines Programms bestimmt, zu dem wir später kommen. In dem Fall des Stop.png's waren es 750 Byte. Der picbuf_stop wird mit den Bilddaten gefüllt; hierbei hilft uns das Programm Converter, welches im Anschluss kurz vorgestellt wird.
static const unsigned char picbuf_stop[750]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd, ........ (Bilddaten)
};
Im Konstruktor der Klasse wird ein neues QPixmap erzeugt.
stop=new Qpixmap();
69
Danach wird dem QPixmap mitgeteilt, an welcher Stelle es die Bilddaten findet und wie groß das Bild ist. Um Speicherzugriffsfehler zu vermeiden, ist es wichtig, dass die Größe richtig angegeben wird. Falls das Programm mit einem Speicherzugriffsfehler terminiert, ist dies eine sehr wahrscheinliche Fehlerquelle. stop­>loadFromData(picbuf_stop,750 );
In der Funktion MyPic::init() wird das Signal pic_stop ausgesendet. emit pic_stop(stop);
Bei der Deklaration des Signals in der Header­Datei war noch nicht klar, auf welches Bild das Argument des Signals zeigen wird. An dieser Stelle wird "stop" als Argument mitgegeben. Es wäre theoretisch auch möglich, dem Signal­ pic_stop() ein anderes Bild als Argument zu übergeben, was aber nicht sinnvoll wäre und nur Verwirrung stiften würde.
70
5.10 Das Hilfsprogramm Converter
Das Converter Programm ist eine Konsolen­Applikation, die man mit dem Pfad zum Bild als Übergabeparameter startet.
z.B. ./converter /home/icmuser/pictures/Stop.png
Dieses kleine Hilfsprogramm ist beim Füllen des Puffers für Bilder der MyPic­Klasse zuständig. Es gibt die Binärdaten des Bildes auf dem Bildschirm in Hexadezimaler Form aus. Die Werte sind durch Kommas separiert, sie können so direkt beim Befüllen des Puffers verwendet werden. Außerdem gibt es die benötigte Puffergröße auf der Konsole aus.
Die Ausgabe sieht wie folgt aus:
­­­­­­­­­­­START­­­­­­­­­­­­­­­­
0x89,0x50,0x4e,0x47,0xd,0xa, ....
­­­­­­­­­­­­END­­­­­­­­­­­­­­­­­­­
Size:750
Listing 3: Konsolenausgabe des Converters
Die Daten zwischen den Markierungen START und END können in die Klasse MyPic kopiert werden. Zu beachten ist, dass das letzte Komma hinter dem letzten Binärwert weggelassen werden muss. Das Programm ist als Binary für Linux und Windows der CD beigefügt. Ebenso die Quellen, Visual­Studio Projekt­Datein und das Makefile für Linux.
71
5.10.1 Vom Button­Click bis zur Anzeige
Dieses Abschnitt beschäftigt sich damit, was alles geschieht, bevor der Benutzer eine Rückmeldung vom System bekommt, nachdem er durch Anklicken eines Buttons eine Aktion anstößt. Auf dem HP­iPAQ wird in der RemotHMI ein Button angeklickt. Dessen Signal clicked() wird ausgesendet und alle Slots, die mit ihm verbunden sind, werden abgearbeitet. Alle DisableButtons haben einen Slot HandleClicked(), der standardmäßig aufgerufen wird, da er im Konstruktor mit dem Signal clicked() verbunden wurde. Ist der DisableButton enabled, so sendet der HandleClicked­Slot ein Signal Clicked() mit großem Anfangsbuchstaben. Dieses Signal ist wiederum mit dem Slot IncVolume() der Klasse Amplifier verbunden. Der Button selbst kennt also keine Funktionalität. Erst mit dem Verbinden von Signalen und Slots wird dem Button eine Bedeutung zugeordnet. Die Amplifier­Klasse sendet ein weiteres Signal aus, welches aus der ReceiverID, dem Opcode, und den Parametern 1­3 besteht.
Die ReceiverID = Amp1ID steht für den Verstärker, der für den Kopfhörerausgang zuständig sein soll. Als Opcode wird VOLUME übergeben. Der Parameter1 wird auf INC (increase) gesetzt, damit die Amplifier Komponente auf Target­Seite weiß, was sie mit der Lautstärke tun soll. Der Parameter2 gibt die Inkremente an.
Dieses Signal wird mit einem Slot der WLanClient­Klasse verbunden. Diese fügt als SenderID noch WLanServerID hinzu und generiert ein High­Level­Event, wie wir es im Framework bereits kennen.
Vom WLanClient werden die Daten über eine Socket Verbindung an den WLanServer geschickt.
Damit sind die Daten auf dem InCarMultimediaSystem angekommen und ein kleiner Teil des Weges einer Nachricht ist zurückgelegt. Die RemoteHMI wird auf dem Target durch den WLanServer repräsentiert. Der WLanServer legt die erhaltene Nachricht in die Queue des MainDispatchers. Anhand des Sender­Typs wird entschieden, welche weitere Verarbeitung geschieht. Eine ApplicationMessage, wie in unserem Framework die High­Level­Events genannt werden, wird an die handleAppMessage Memberfunktion des MainDispatchers delegiert. In dieser Methode wird anhand der ReceiverID entschieden, welcher Komponente die Nachricht ausgeliefert wird. Bei dieser Nachricht wird entschieden, dass sie in die Queue 72
der Amp1 Komponente gehört. In der Amp1­Komponente angekommen, wird wieder anhand des Sender­Typs entschieden, was mit der Nachricht zu tun ist. Hier wird unter Zuhilfenahme des Proxies eine MOST­Message erstellt. Die MOST­Nachricht wird dann dem MainDispatcher in die Queue gelegt, dieser erkennt anhand des Sender­Typs, dass es sich diesmal um eine Nachricht für den MOST­Bus handelt. Die Nachricht wird an den MOST­
Tranceiver­Thread weitergeleitet, der Anhand des FunctionBlocks und der InstanceID weiß, zu welchem Device die MOST­Nachricht gesendet werden muss. In unserem Falle ist dies beispielsweise das Device mit der ID 0x103. Der MOST­Tranceiver schickt also die Nachricht über seinen MOST­Treiber an das physikalische Gerät. Dort angekommen, wird die Nachricht ausgewertet und die Lautstärke verstellt. Jetzt hat der Benutzer seine erste Rückmeldung in akustischer Form erhalten.
Die Nachricht ist vom WLAN­Server zum MainDispatcher von hieraus zum Amplifier und wieder zurück zum MainDispatcher in den Tranceiver­Thread. Allein auf dem InCarMultimediaSystem waren hierfür mehrere Prozess­ und Thread­Switches nötig damit die Nachricht ihr Ziel erreicht. Dazu kommt noch die Verbindung zum HP­iPAQ.
Die Hälfte des Weges ist nun zurückgelegt. Jetzt muss die Information mit der neuen Lautstärke wieder zurück zum HP­iPAQ übertragen werden. Hierbei geht sie den Weg in umgekehrter Reihenfolge.
73
5.11 Qt Linguist
Qt bietet mit dem Qt Linguist einen optimalen Service zur Übersetzung der eigenen Programme in verschiedene Sprachen. Dieser Abschnitt zeigt, wie der Linguist arbeitet. Die Beispiele orientieren sich an der Onlinedokumentation [Troll­2006] und dem Buch [Blan­2004].
Bei großeren Projekten sind mehrere Personen bei der Übersetzung beteiligt. Es gibt Release Manager, die einen groben Überblick über das komplette System haben müssen, die Übersetzer, die meistens mehrere Sprachen beherrschen und die Programmierer. Sie müssen wissen wie man Applikationen entwickelt, die sich die übersetzen Texte zunutze machen. Für alle Beteiligten des Übersetzungsprozesses muss gewährleistet werden, dass sie nicht überfordert sind. So mutet man den Übersetzern nur soweit Kenntnisse im Computerbereich zu, dass sie Programme starten können und mit Textverarbeitungsprogrammen umgehen können.
Programmierer Die Programmierer müssen darauf achten, dass sie Qstring verwenden, falls ein Text für den Endanwender sichtbar ist. QString benutzt intern Unicode und ist damit für alle Sprachen gerüstet.
Den in Anführungszeichen stehenden Text umschließt man mit der tr()­Funktion.
MyWidget::MyWidget()
{
Qlabel *label = new Label ( tr("Hallo Welt"), this);
}
Falls man Text verwendet und sich nicht in einer Memberfunktion einer von QObject oder QWidget abgeleiteten Klasse befindet, hat man die Möglichkeit die Funktion translate() von QApplication zu verwenden. Die Übersetzung eines Textes ist von mehreren Aspekten abhängig. Dem Kontext, in dem die Übersetzung stattfindet, dem Text und dem optionalen Kommentar.
74
Kontext::tr (Text,Kommentar);
Der Kontext ist im Falle der tr­Funktion vom Objekt bereits vorgegeben. Im oberen Beispiel wäre der Kontext „MyWidget“. Im Falle von translate() muss der Kontext explizit angegeben werden.
Die Übersetzung von Strings verschiedener Klassen ist unabhängig voneinander.
So könnte das Wort “Löffel“ in einer Klasse die Bedeutung von „Besteck zum Essen“ bekommen und in einer anderen Klasse die Bedeutung von „Ohren eines Hasen“.
Ein Beispiel hierzu.
MyWidget1::tr("Bank","Geld");
MyWidget2::tr("Bank","Sitzgelegenheit");
Der Kommentar ist sehr wichtig, da es bei vielen Wörtern mehrere Möglichkeiten der Übersetzung gibt. Er, dient dem Übersetzer die richtige Wahl zu treffen. Wer sich in das Thema vertiefen möchte, dem empfehle ich die sehr übersichtliche Online Dokumentation.
Die Release Manager kümmern sich um den nächsten Schritt.
Um das Programm in eine andere Sprache zu übersetzen, erzeugen sie mit dem Programm lupdate „.ts“­Dateien. Dabei extrahiert lupdate allen Text, der vom Endbenutzer gesehen wird, unter der Voraussetzung, dass die Programmierer fleißig tr() in ihrem Quellcode verwenden. Für jede Sprache wird gewöhnlich eine „.ts“­Datei erzeugt.
Bei der Extraktion des zu übersetzenden Textes gibt es natürlich Probleme, wenn der Text aus Variablen besteht, da der Übersetzer dann nur die Variable kennen würde und nicht den Text, den er übersetzen soll.
Bsp.:
const char* beschreibung ="Ein Text der übersetzt werden soll!";
Qstring uebersetzung = tr (beschreibung);
Ein ähnlicher Fall tritt ein, wenn Zeichenketten dynamisch erzeugt werden.
tr("Hallo " + name + "!");
75
Texte außerhalb von tr() und translate()­Funktionen werden von lupdate nicht gefunden und werden deshalb nicht extrahiert. Um sie dennoch zum Extrahieren auffindbar zu machen, werden sie in die MACRO's QT_TRANSLATE_NOOP bzw. QT_TR_NOOP eingeschlossen. Die MACROS liefern nur den Wert zurück und machen sonst nichts! Aus QT_TR_NOOP("eins") wird "eins". Sie dienen nur lupdate, diese Textstellen für den Übersetzungsprozess auffindbar zu machen, damit sie extrahiert werden können.
void MyWidget::ShowNumbers()
{
static const char * const numbers[] = {
QT_TR_NOOP ("eins"),
QT_TR_NOOP ("zwei"),
QT_TR_NOOP ("drei"),
QT_TR_NOOP ("vier"),
QT_TR_NOOP ("fünf")
};
for (int i=0;i<5;i++) listBox->insertItem(tr( numbers[i] ) , i);
}
Beim Übersetzen ist oft die Reihenfolge der Argumente wichtig, da die Sätze unterschiedlich gebildet werden. Aber auch hierfür gibt es in Qt eine Lösung. Bei Argumenten ist darauf zu achten, dass QString::arg() verwendet wird. Außerdem kann der Übersetzer mit einer Variablen nichts anfangen, wenn er deren Inhalt nicht kennt.
void MyWidget::zeigeFortschritt(int akt,int max,const QString& Betreff )
{
myLabel.setText(tr("E-Mail %1 von %2 versendet.\nVersende E-Mail: %3")
.arg(akt)
.arg(max)
.arg(Betreff)
);
}
Die Aufgabe der Übersetzer ist es mit Hilfe des Qt­Linguist .ts­Dateien zu bearbeiten und für die neue Sprache eine Übersetzung bereitzustellen. Die .ts­Dateien liegen im XML­Format vor und können auch per Hand editiert werden.
Mit dem Programm lrelease wird aus den „.ts“­Dateien eine .qm­Datei erzeugt. Nur diese wird zum Schluss benötigt. Wenn man Vergleiche zur Programmierung zieht, könnte man die „.ts“­Dateien mit Quellcode vergleichen und die „.qm“­Dateien mit Objekt­Dateien. Beide sind Plattform unabhängig.
76
Für jede Sprache, die man unterstützen möchte, macht man einen Eintrag in der Projekt­
Datei.
TRANSLATIONS =
my_app_de.ts \
my_app_uk.ts \
my_app_no.ts \
Beim Starten von lupdate und lrelease gibt man als Kommandozeilenparameter die Projekt­
Datei mit an (MyApp.pro). Diese Projekt­Datei sorgt dafür, dass z.B. eine deutsche, eine englische und eine norwegische „.ts“­Datei erzeugt wird.
Am Anfang eines Programms muss der Programmierer die richtige Übersetzung laden. Hierfür
gibt
es
die
Funktionen
QTranslator::load() und Qapplication::installTranslator().
Frühere Versionen von Qt verwendeten die Tools findtr, msg2qm und mergetr. Es gibt ein Tool qm2ts um die alten .qm­Dateien nach .ts­Dateien zu wandeln.
Um verschiedene Encodings zu unterstützen gibt es die Klasse QTextCodec, bei der ich auch nur auf die Online Dokumentation verweisen möchte.
Die Funktion QTranslator::load() nimmt einen Dateinamen entgegen und den Ordner, in dem sich die Datei befindet. Im Falle, dass die Übersetzungsdatei im gleichen Verzeichnis wie das Programm liegt, kann qApp->applicationDirPath() als zweiter Parameter verwendet werden.
Je nach Sprache wird ein anderer Dateiname benötigt, deshalb ist es von Vorteil, wenn man als Dateiname "my_app_" + QtextCodec::locale() verwendet. Es ist auch möglich, unabhängig von der Sprache, die auf dem PC eingestellt ist, eine Übersetzung zu laden.
Die locale­Funktion versucht die Locale so genau wie möglich zu bestimmen. Sie liefert außer der Sprache eventuell noch Land und Kodierung. Befindet man sich in Österreich, könnte die locale()­Funktion “de_AT.ISO8859-15“ zurückliefern, so hätte man mit dem Dateinamen ein Problem.
Der Load Befehl lässt Spielraum beim Dateinamen zu, um dies abzufangen. Der Load­Befehl versucht in diesem Fall zuerst die Datei “my_app_de_AT.ISO8859-15.qm“ zu laden. Existiert diese nicht, probiert der Load­Befehl die Datei “my_app_de_AT“ zu laden. Bis er schließlich mit der Datei “my_app_de.qm“ fündig wird. [Blan­2004], [Troll­2006]
77
5.12 TMAKE
„tmake“ ist ein Perl­Script, das ursprünglich von der Firma Trolltech geschrieben wurde, um automatisch Makefiles generieren zu lassen. Es unterstützt mehrere Compiler und verschiedene Betriebssysteme. Das automatische Generieren von Makefiles ist beim Programmieren mit Qt sehr wichtig, da die meisten Quelldateien erst noch durch den Meta­
Object­Compiler verändert werden müssen, und der Aufruf des Meta­Object­Compilers für viele Dateien in das Makefile aufgenommen werden muss. Für heutige Versionen von Qt wird an Stelle von TMAKE das Tool QMAKE genutzt. Es taucht in vielen HowTo's auf und wird auch mit QTopia ausgeliefert.
5.13 QMAKE
QMAKE wird bei der Entwicklung von Qt­Programmen genutzt, um Projektdateien (.pro) und Makefiles generieren zu lassen. Das Kommando „qmake ­project“ veranlasst qmake dazu, eine Projektdatei zu erstellen (PROJEKTNAME.pro), diese Datei ist noch plattformunabhängig.
Ruft man „qmake“ ohne Übergabeparameter auf, erstellt QMAKE aus der Projektdatei ein plattformspezifisches Makefile, welches dann mit dem Befehl „make“ die ausführbare Datei (Binary) erstellt. Falls man unter Windows mit Visual Studio entwickelt, so verwendet man „nmake“ anstelle von „make“.
5.14 MAKE
Das Programm „make“ hilft beim Erzeugen und Installieren von Binaries. In dem sogenannten Makefile wird hinterlegt, was dabei zu tun ist. In einem Makefile stehen verschiedene Targets, die von verschiedenen Dateien abhängig sein können und Regeln, um die Targets zu erzeugen. Falls „make“ ohne Paramter aufgerufen wird, erzeugt es das Haupt­
78
Target. Objekt­Dateien werden als Sub­Targets angegeben, sie hängen von den dazugehörigen Quelldateien ab. Ein Target wird nur dann neu erstellt, wenn die Dateien, von denen das Target abhängig ist, neuer als das Target selbst sind; dadurch ist es möglich, den Build­
Vorgang zu beschleunigen. Das Haupt­Target ist meist das Binary, welches erstellt werden soll. Es hängt nicht von Quelldateien, sondern von Object­Dateien ab, die dann erst von den Quelldateien abhängig sind. Speziell bei Qt ist es so, dass die Quelldateien erst durch den Meta­Object­Compiler verändert werden müssen, so dass selbst die Object­Dateien nicht direkt von den Quell­Dateien, sondern von den „moc_*.cpp“­Dateien abhängig sind. So entsteht eine Hierarchie, die, um sie einzutippen und auf dem aktuellen Stand zu halten, eine gewisse Zeit in Anspruch nehmen würde. In der ersten Spalte eines Makefiles stehen die Targets, gefolgt von einem Doppelpunkt und danach deren Abhängigkeiten. In den darauf folgenden Zeilen stehen mit einem Tabulator eingerückt die Befehle, die nötig sind, um das Target zu erzeugen. Ein rückläufiger Schrägstrich am Zeilenende bedeutet, dass die nächste Zeile so betrachtet werden soll, als stünde sie hinter dem dem rückläufigen Schrägstrich. Hiermit will man überlange Zeilen vermeiden. WLanClient.o: WLanClient/WLanClient.cpp WLanClient/WLanClient.h \
WLanClient/SocketMessageTypes.h \
Maxicom/Maxicom.h \
Tuner/Tuner.h \
Global.h \
TThread/TThread.h \
CMessage.h \
Events.h \
Device/Device.h
$(CXX)
-c
$(CXXFLAGS)
$(INCPATH)
-o
WlanClient.o
WlanClient/WLanClient.cpp
\
Listing 4: Makefile
Dieses Beispiel zeigt, von welchen Dateien das Target WLanClient.o abhängig ist. Die untere Zeile stellt den Befehl dar, mit dem das Target erzeugt wird. „$(CXX)“ ist der Inhalt der Variablen CXX, der am Anfang des Makefiles zugewiesen werden muss. In Makefiles ist es üblich, mit vielen Variablen zu arbeiten, damit ist es möglich, z.B. den Compiler an einer zentralen Stelle für das komplette Makefile zu wählen. Wenn man Binaries für den HP­iPAQ generieren möchte, so weist man der Variablen CXX „arm­linux­g++“ zu. Normalerweise 79
erledigt dies QMAKE, falls aber QMAKE nicht richtig konfiguriert wurde, ist dies eine wichtige Stelle, an der man ein Fehlverhalten feststellen kann. Die obige Zeile wird also zu „arm­linux­g++ ­c ...“.
Wenn die Zuweisung von MOC, UIC und CXX wie folgt in dem Makefile vorhanden sind, dann wird das Binary für den PC erzeugt.
MOC
UIC
CXX
= /usr/share/qt3/bin/moc
= /usr/share/qt3/bin/uic
= g++
80
5.15 Executeables für den HP­iPAQ erzeugen
Da man nicht für Qt­X11 in der Version 3.xx kompilieren möchte, die man auf seinem PC verwendet, sondern für Qt­Embedded in der Version 2.xx, setzt man das QTDIR entsprechend dem Ordner, in dem man die Libraries und Header für den HP­iPAQ gespeichert hat. Da der User­Interface­Compiler und der Meta­Object­Compiler für Version 2.xx und 3.xx unterschiedlich sind, ist es praktisch, dass diese in QTDIR/bin gesucht werden. Hier kopiert man noch zusätzlich die Dateien uic und moc hinein.
export QTDIR=/home/XYZ/QTDIR
Nachdem das QTDIR richtig gesetzt wurde, ist es nötig, QMAKE mitzuteilen, für welches Target er Makefiles erzeugen soll. Am einfachsten ist es die Umgebungsvariable QMAKESPEC richtig zu setzen. Mit den Qtopia­Versionen von Trolltech werden Spezifikations­Dateien für die verschiedensten Targets mitgeliefert.
Falls QMAKESPEC gesetzt ist, liest QMAKE diese Spezifikation ein und generiert dann die Makefiles für das entsprechende Target. Setzt man QMAKESPEC nicht, so wird das Makefile so generiert, dass es Binaries für den eigenen PC baut.
export QMAKESPEC=/home/XYZ/QTDIR/mkspecs/qws/linux-ipaq-g++
Variablen wie CXX werden durch diese Spezifikations­Datei richtig gesetzt. Sie zeigt nun auf „arm­linux­g++ ­DQT_QWS_IPAQ“. Damit dieser Compiler gefunden wird, muss noch der Pfad, in dem er sich befindet, zur PATH­Variablen hinzugefügt werden.
export PATH=/usr/local/arm/oe/bin:$PATH
Diese Zeilen habe ich in einem Script Namens buildscript.sh zusammengefasst, damit man sie nicht jedes mal erneut eintippen muss.
export QTDIR=/home/XYZ/QTDIR
export QMAKESPEC=/home/XYZ/QTDIR/mkspecs/qws/linux-ipaq-g++
export PATH=/usr/local/arm/oe/bin:$PATH
Listing 5: buildscript.sh
81
Um für den HP­iPAQ zu bauen gibt man folgende Befehle auf der Console ein:
. ./buildscript.sh ( Umgebungsvariablen setzen )
qmake ­project ( plattformunabhängige Projektdatei erzeugen )
qmake ( plattformspezifisches Makefile erstellen )
make ( Binary erzeugen )
5.15.1 Konsole und Umgebungsvariablen
Dem Aufruf des Build­Skriptes werden zwei Punkte vorangestellt; der erste Punkt ist kein Schreibfehler, sondern nötig, um die für die nachfolgenden Tools erforderlichen Umgebungsvariablen dauerhaft zu exportieren. Durch den Punkt wird bewirkt, dass das Skript innerhalb des Konsolenprozesses (Vaterprozess) ausgeführt und nicht wie üblich geforkt wird. Die nachfolgend durch die Compiler­Aufrufe erzeugten Prozesse kennen damit die gesetzten Variablen. Ansonsten gingen die gesetzten Umgebungsvariablen nach Beendigung des Kindprozesses verloren. Abbildung 24: Forken bei Konsolen­Applikationen
82
5.16 Unterscheidung Qt/X11 und Qt/E
Da das Remote­Projekt für Desktop­Rechner ebenso gültig sein soll wie für den HP­iPAQ, ist beim Übersetzungsprozess eine Unterscheidung notwendig. Ebenso benötigt der Programmierer eine Unterscheidungsmöglichkeit in seinem Quellcode, mit der er auf das gerade aktuelle Zielsystem eingehen kann.
Dabei sind ihm die Compilerflags im Makefile behilflich. Compilerflags in dem Makefile für iPAQ
CXXFLAGS = -pipe -DQWS -fno-exceptions -fno-rtti -Os
-DQT_NO_DEBUG
Compileflags ( Qt/X11 )
CXXFLAGS
=
-pipe
-Wall
-W
-O2
-D_REENTRANT
-DQT_NO_DEBUG
-DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT
Mit dem Parameter ­D übergibt man dem Compiler Präprozessordirektiven, so wird mit den Compilerflag ­DQWS, „QWS“ definiert. Im Quellcode kann man damit unterscheiden, ob es sich nun um einen Compiliervorgang für den iPAQ oder den Desktop­Rechner handelt.
#ifdef QWS
//iPAQ
#include <qpe/qpeapplication.h>
#else
//PC
#include <qapplication.h>
#endif
int main( int argc, char **argv ){
#ifdef QWS
QPEApplication a( argc, argv );
#else
QApplication a( argc, argv );
#endif
//...
//show the Form
#ifdef QWS
83
#else
#endif
hmi->showFullScreen();
hmi->show();
}
Listing 6: Ausschnitt aus InCarMultimedia main.cpp
Das Programm ist auf dem iPAQ eine QPEApplication, während es sich auf dem Desktop­
Rechner um eine QApplication handelt. Dementsprechend ändern sich die benötigten Includes. Des Weiteren wird die gleiche Applikation auf dem iPAQ im Vollbild­Modus gestartet, während sie auf dem Desktop­Rechner in einem Fenster läuft.
84
5.17 Eigene Widgets
Für viele Applikationen ist es ausreichend, die Standard­Widgets von Qt zu verwenden.
Es ist aber auch möglich, neue Widgets zu erzeugen oder Widgets von anderen Widgets abzuleiten, und sie um die gewünschte Funktionalität zu erweitern.
5.17.1 Bar
Eigene Widgets erstellt man, indem man von QWidget ableitet und die Event­Handler für das Zeichnen und für die Maus­Aktionen wie z.B. mouseMoveEvent und mousePressEvent reimplementiert. Unsere Anzeige­Bar soll nur Werte anzeigen können, deshalb ist es nicht nötig, die Mausbehandlung zu reimplementieren.
Die neu erstellte Bar soll ähnlich der Progressbar einen Wert anzeigen können. Es gibt einen Minimalwert (mMinValue), einen Maximalwert (mMaxValue) und den aktuellen Wert, der zur Anzeige gebracht wird (mValue).
Des Weiteren hat die Bar zwei Farbwerte, in der sie später gezeichnet wird (mBorderColor, mBarColor).
Die Bar besitzt zwei verschiedene Anzeige­Modi.
Wenn mMiddleBar auf true gesetzt ist, füllt sich die Bar von der Mitte nach außen.
So würde die Bar aussehen, wenn der aktuelle Wert 40 ist und die Bar von 0 bis 100 reicht. Abbildung 25: Bar­Widget 40%
85
Wenn die Bar von ­50 bis 50 reicht und der aktuelle Wert ­10 beträgt erhält sie das gleiche Aussehen.
Abbildung 26: Bar­Widget 70%
Der aktuelle Wert wird im Zusammenhang mit dem Minimalwert und dem Maximalwert ausgewertet. Ist der aktuelle Wert näher am Maximalwert, schlägt die Bar nach rechts aus. In diesem Fall ist die Bar zu 70% gefüllt.
Abbildung 27: Bar­Widget 40% mMiddleBar=false
Im normalen Anzeigemodus (mMiddleBar==false) verhält sich die Bar wie eine Progressbar und füllt sich von links nach rechts.
Die Berechnung des Ausschlags ist nur Prozent genau, aber dies sollte für unseren Zweck ausreichen.
#ifndef _BAR_H_
#define _BAR_H_
#include <qwidget.h>
#include <qcolor.h>
class Bar: public QWidget
{
Q_OBJECT
private:
int mMinValue;
int mMaxValue;
int mValue;
int mBorder; //Randbreite
bool mMiddleBar;
QColor mBorderColor;
QColor mBarColor;
protected:
void paintEvent(QPaintEvent*);
86
public:
Bar(QWidget *parent = 0, const char *name = 0);
QSize sizeHint();
bool setProperty ( const char * name, const QVariant & value );
public slots:
void setValue(int);
};
#endif //_BAR_H_
Listing 7: Header­Datei Bar.h
Die Funktion sizeHint() wird überschrieben, sie liefert Größenangaben, die den Layout­
Managern nützlich sind.
QSize Bar::sizeHint()
{
return QSize(50,5);
}
Im Konstruktor der Klasse könnte man die Funktion setSizePolicy(...) aufrufen um ein Standardverhalten bei den Layout­Managern festzulegen.
Für eine solche Bar ist in der Y­Richtung eine feste Größe (QSizePolicy::Fixed) sinnvoll und in X­Richtung kann sich die Bar auf dem verbleibenden Platz ausdehnen (QSizePolicy::Expanding).
Zusammen mit den Werten von sizeHint bedeutet dies, dass die Bar die Höhe 5 bekommt und in X­Richtung den restlichen freien Platz zugeteilt bekommt. Arbeitet man mit dem Qt­
Designer, kann man diese Werte auch mit ein paar Mausklicks überschreiben. Mit der Funktion setProperty kann man alle selbst definierten Properties überschreiben.
So lassen sich Minimal­ und Maximalwerte im Qt­Designer eintragen, das gestaltet das Arbeiten im Designer genauso einfach wie mit Qt eigenen Widgets.
Leider zeigt der Qt­Designer beim Modellieren die selbsterstellten Widgets nur in Form einer festen Grafik an. Man sollte für die eigenen Widgets eine Grafik auswählen, damit man gleich erkennen kann, um welche Art von Widget es sich handelt. Beim Verbinden von Signal und Slots im Designer per Drag 'n Drop ist es sehr hilfreich, wenn die Widgets visuell 87
voneinander unterschieden werden können.
Die paintEvent­Methode bedient sich der Funktionen width() und height(), um die tatsächliche Größe des Widgets zu erfahren. Mit Hilfe des QPainters wird ein Rechteck in der Farbe des Randes gezeichnet (mBorderColor).
Wird mBorderColor nicht gesetzt, verwendet das Widget stattdessen die Hintergrundfarbe.
void Bar::paintEvent(QPaintEvent*)
{
//...
QPainter painter(this);
//...
painter.fillRect(0,0,width(),height(),mBorderColor);
//...
}
In beiden Anzeigemodi (mMiddleBar==true) und (mMiddleBar==false) wird unterschiedlich verfahren.
Die Breite und die Position des zu zeichnenden Balkens hängen vom aktuellen Wert, des Minimalwerts, des Maximalwerts, dem Anzeigemodus und der Randbreite ab. Die Berechnung erspare ich mir an dieser Stelle, sie kann in der Quellcode­Datei Bar.cpp nachgelesen werden.
88
5.18 KUI­Viewer
Wie die meisten Programme, die für KDE geschrieben wurden, fängt auch dieses Programm mit einem „K“ an. Der KUI­Viewer zeigt Dateien mit der Endung “.ui“ an, wie sie vom Qt­Designer erstellt werden. Qt ist ein plattformübergreifendes GrafikFramework, das versucht, sich an das native Aussehen des Betriebssystems anzupassen. So sehen die gleichen Qt­Widgets unter Windows anders aus als unter Linux. Um das Aussehen eines Qt­Programms zu ändern, kann man es mit der Option –style starten. ./InCarMultimedia –style=Windows
Listing 8: Styleangaben für Qt­Programme
Weitere Styles sind:
●
Motif
●
CDE
●
SGI
●
Platinum
●
MotifPlus
●
Windows XP
●
Mac
Bei der Programmierung der eigenen Widgets wird diese Style­Angabe nicht beachtet, so dass das „Bar“­Widget überall identisch aussieht. Das Programm KUI­Viewer kann die eigenen Widgets nicht darstellen, da in der UI­Datei die Printfunktion des Widgets nicht enthalten sind. Die in Qt enthaltenen Widgets hingegen können mit diesem Programm in den verschiedensten Styles angezeigt werden. 89
Folgende Grafik zeigt den Settings­Tab der HMI in den Styles Default, Light, Platinum und Keramik. Da die aktuelle Remote­HMI zum Teil aus eigenen Widgets besteht, macht es wenig Sinn, diese mit dem KUI­Viewer anzuzeigen. Hier wird ein Stand zu Anfang des Projekts gezeigt.
Abbildung 28: verschiedene Qt Styles in KUI­Viewer
Die Styles Windows XP und Mac sind eine Ausnahme, sie basieren auf der Design­Engine der jeweiligen Plattform.
90
5.19 Remote­HMI in Qt
In Qt ist es üblich mit dem Signal­Slot Prinzip zu arbeiten. Wenn ein Button angeklickt wird, geschieht nur etwas, wenn das clicked­Signal des Buttons auch zuvor mit einem Slot verbunden wurde. Um also Funktionalitäten in ein Programm zu bringen, ist es nötig Slots anzubieten. Es ist nicht sinnvoll alle Slots in einer Klasse unterzubringen, deshalb habe ich für jedes Gerät, das in der HMI verwaltet werden soll, eine Klasse erstellt, die die gewünschten Funktionalitäten implementiert. Alle dieser Klassen erben von der Klasse Device, die die grundlegenden Fähigkeiten enthält, die bei allen Klassen gleich sind. So ist in ihr z.B. die ComponentID gespeichert. Am Beispiel der Klasse Amplifier möchte ich nur grob den Ablauf erläutern. Hierzu schauen wir uns die Header­Datei der Klasse an, um einen Überblick über die Signals und Slots zu bekommen, die die Klasse anbietet.
#ifndef __AMPLIFIER_H__
#define __AMPLIFIER_H__
#include "Events.h"
#include "CMessage.h"
#include "Device.h"
class Amplifier : public Device
{
Q_OBJECT
private:
int
int
int
int
int
int
mBass;
mFader;
mVolume;
mTreble;
mBalance;
mSubwooferLevel;
public:
Amplifier(QWidget* parent,const char * name);
signals:
void
void
void
void
void
void
BassChanged(int);
FaderChanged(int);
VolumeChanged(int);
TrebleChanged(int);
BalanceChanged(int);
SubwooferLevelChanged(int);
void AppMessage(int,int,int,int,int);
91
public slots:
void
void
void
void
void
void
SetBass(int Bass);
SetFader(int Fader);
SetVolume(int Volume);
SetTreble(int Trebble);
SetBalance(int Balance);
SetSubwooferLevel(int SubwooferLevel);
void
void
void
void
void
void
IncBass();
IncFader();
IncVolume();
IncTreble();
IncBalance();
IncSubwooferLevel();
void
void
void
void
void
void
DecBass();
DecFader();
DecVolume();
DecTreble();
DecBalance();
DecSubwooferLevel();
void setBassboost(bool);
void setLoudness(bool);
};
void handleAppMessage(const CMessage& msg);
#endif //__AMPLIFIER_H__
Listing 9: Datei Amplifier.h
Am Beispiel der Bass­Einstellung möchte ich kurz den Ablauf in Qt erläutern. Wie in Listing 9 zu sehen gibt es das Signal AppMessage. Dieses Signal wird von der Klasse WLanClient entgegen genommen und in eine CMessage des Typs AppMessage umgewandelt und danach über eine Socket­Verbindung an den WLanServer gesendet, der sich im InCarMultimedia­
System befindet. Wenn man nun den Button drückt, der den Bass erhöhen soll, wird dessen clicked()­Signal aufgerufen, dieses musste zuvor mit dem Slot IncBass() der Klasse Amplifier verbunden werden. Dies geschieht, wie bereits beschrieben, per Drag 'n Drop.
Nun schauen wir uns den Slot IncBass wie er in der Datei Amplifier.cpp implementiert ist näher an.
92
void Amplifier::IncBass()
{
emit AppMessage(mComponentID,BASS,INC,1,0);
}
Listing 10: Slot IncBass() Amplifier.cpp
Der Slot IncBass() ist sehr stupide, er macht nichts anderes, als das Signal AppMessage auszusenden. Der erste Parameter der AppMessage ist der Empfänger. In der ComponentID der Amplifier­Klasse ist Amp1ID hinterlegt. Der Empfänger ist also der Amplifier, der für den Kopfhörerausgang zuständig ist. Die nächsten Werte sind Opcode und Parameter der Nachricht.
Um den Bass zu verringern, wird das gleiche Signal ausgesendet. Nur sind die Parameter unterschiedlich.
emit AppMessage(mComponentID,BASS,DEC,1,0);
Die gleiche Funktionalität ist für Fader, Volume, etc. implementiert. Der WLanClient besitzt den Slot sendAppMessage(int,int,int,int,int) der das Signal AppMessage entgegennimmt und noch den Absender hinzufügt, der aber für alle Klassen gleich ist; nämlich WLanServer. Da Fader, Bass, Volume etc. alle über das gleiche Signal geändert werden, ist es nur nötig, dieses eine Signal AppMessage(int,int,int,int,int) mit dem Slot sendAppMessage(int,int,int,int,int) der Klasse WLanClient zu verbinden. Die zurückkommenden Update­Nachrichten werden von dem Slot­handleAppMessage(cont Cmessage&) verarbeitet. Um beim Beispiel des Basses zu bleiben, wird dieser, wenn er in einer Update­Nachricht ankommt, in der Variablen mBass gespeichert und das Signal BassChanged(int) versendet. Dieses Signal wird mit dem Slot setValue(int) des Objekts BassBar, welches vom Typ Bar ist, verbunden. Die BassBar ändert daraufhin ihre Anzeige. Falls man das Signal­Slot Prinzip einmal verstanden hat, wird man schnell merken, dass das Programmieren in wildes Geklicke ausartet. Ein neues Gerät ist schnell hinzugefügt und durch ein paar Klicks in der HMI integriert. 93
5.20 Icon für den PDA­Desktop erstellen
Auf PDAs sind Desktop­Icons zum Starten von Programmen sehr essentiell, da man keine Tastatur hat, um den Programmnamen auf der Konsole einzutippen. Selbstverständlich ginge dies auch mit der Bildschirmtastatur, es wäre aber zu umständlich. Alle Programme ins Startmenü mit aufzunehmen wäre ebenfalls möglich, würde aber dazu führen, dass man dort den Überblick verliert. Bei Opie ist es so geregelt, dass der Desktop durch Karteireiter unterteilt ist, dieser gibt den Bereich der Software vor (PIM, Applications, Games, ...). In jedem dieser Karteireiter befinden sich Symbole Abbildung 29: ScreenShot Opie (Games­Tab) zum Starten der dort enthaltenen Programme. Um ein solches Icon zu erstellen legt man eine .desktop­Datei an. In unserem Fall ist dies die Datei
/opt/QtPalmtop/apps/Games/icm.desktop.
Das Verzeichnis „Games“, in dem die Datei erstellt wurde, gibt an, in welchem Karteireiter das ICM­Icon angezeigt wird. Der Games Ordner wurde gewählt, da er nicht so überfüllt ist und man so das Programm­Icon gleich findet. Nun zum Inhalt der icm.desktop Datei
[Desktop Entry]
Exec=icm
Icon=icm
Type=Application
Name=InCarMultimedia
Comment=Remote ICM HMI
Listing 11: “icm.desktop“­Datei
Exec gibt die ausführbare Datei an, dabei ist zu beachten, dass die ausführbare Datei im Verzeichnis /opt/QtPalmtop/bin/ gesucht wird. Icon ist das Icon, welches angezeigt wird. In unserem Projekt ist es die Datei icm.png, hier ist zu beachten, dass die Endung weggelassen wird und diese Datei diesmal im Ordner /opt/QtPalmtop/pics/ zu liegen hat.
94
5.21 Auslieferung der Software an den PDA
Um die Software auf dem PDA zu installieren, könnte man in Zukunft ein Paket erstellen, welches man mit dem Paket­Manager IPKG ausliefert, der der Distribution Familiar bereits beiliegt. Da das Projekt nicht vollständig fertiggestellt ist, und es öfter zum Testen auf den iPAQ gespielt werden muss, wurde zu diesem Zweck ein kleines Script geschrieben, das die Arbeit des Übertragens und Installierens erledigt. #/bin/sh
echo "fetching file...."
wget http://141.100.47.9/InCarMultimedia
echo "changing rights -> executeable"
chmod +x InCarMultimedia
echo "move file to bin-folder ..."
mv ./InCarMultimedia /opt/QtPalmtop/bin/icm
Listing 12: Script for fetching and installing file
Das Script greift mit der Konsolenapplikation wget auf meinen Webserver und lädt sich die Datei InCarMultimedia herunter, danach werden die Rechte der Datei auf “ausführbar“ gesetzt und zum Schluss noch in das richtige Verzeichnis verschoben, so dass es vom Desktop aus gestartet werden kann. Wenn man sich mit SSH auf dem iPAQ einloggt, kann man dieses Script vom PC aus starten.
95
6 Entwicklung einer HMI für Mobiltelefone
Um eine Remote­HMI für das Siemens­S65 und andere Mobiltelefone entwickeln zu können, ist es nicht nur nötig, einige Hardware Merkmale zu kennen, sondern vor allem über die Möglichkeiten der Software Bescheid zu wissen. Die nachfolgenden Betrachtungen beleuchten diese Möglichkeiten, insbesondere wird auf die Entwicklung mit Java 2 Micro Edition eingegangen. 6.1 Betriebssysteme für Mobiltelefone
Handys haben verschiedene Betriebssysteme, mache laufen mit SymbianOS, andere mit einem Microsoft Windows, das speziell für Handys entwickelt wurde. Von dem Hersteller Palm, der eher aus dem PDA Bereich bekannt ist, gibt es ebenfalls eine modifizierte Version des Betriebssystems PalmOS, welches für Handys angepasst wurde. Mittlerweile gibt es auch Handys, die Linux als Operating­System einsetzen. Vereinzelte Handy­Hersteller benutzen ein selbst entwickeltes Betriebssystem; diese Vielfalt an Betriebssystemen erfordert eine Zwischenschicht, auf die Softwareentwickler aufsetzen können. 6.2 Java
Java hat sich im PC Bereich schon lange bewährt. Die Java Virtual Mashine (JVM) bietet den Software Entwicklern einen sogenannten OS­Abstraction­Layer, mit dem sie vom Betriebssystem unabhängig werden. Java ist wegen seiner sehr hohen Ansprüche aber nur bedingt für den Einsatz im Handy geeignet; für Mobiltelefone und Geräte mit knappem Speicher wurde deshalb J2ME (Java 2 Micro Edition) eingeführt.
96
6.3 J2ME
Neben dem Einsatz in Mobiltelefonen, findet man die Java 2 Micro Edition auch in Set­Top­
Boxen, Video­Telefonen, PDAs, Pagern und einigen anderen Geräten, die ebenfalls über geringfügige Speicherkapazität und Rechenleistung verfügen. Der größte Teil der Java 2 Micro Edition ist eine Untermenge von Java2SE. Teile, die hingegen nicht zur Untermenge von Java2SE gehören, dürfen den Java Namensraum nicht benutzen. J2SE
J2ME
CDC (JVM)
CLDC
(KVM)
J2SE (JVM)
Abbildung 30: J2ME & J2SE im Vergleich (angelehnt an [Schm­2004])
Alle Pakete, die zu java.util.* gehören, gibt es auch in J2SE, sie gehören somit zur Schnittmenge. Die Pakete in javax.microedition.midlet.* hingegen gibt es in der J2SE nicht, dies kann man auch deutlich am Namensraum erkennen, der nicht mit “java“ sondern mit “javax“ beginnt. Die Micro Edition von Java ist in drei Teile unterteilt, dies sind die sogenannten configurations, profiles, zusätzlich gibt es noch weitere optionale Pakete. Je nach Hardware kann so die Micro Editon optimal konfiguriert werden. [Schm­2004]
6.3.1 Configurations
Konfigurationen sind Spezifikationen, die den Funktionsumfang der virtuellen Maschine beschreiben, sie bestehen aus einen minimalen Satz an Klassenbibliotheken, die die notwendigen APIs bereitstellen, um Programme für eine bestimmte Geräteklasse zu 97
entwickeln. Für Java ME gibt es bisher zwei Konfigurationen, die CDC (Connected Device Configuration) und die CLDC (Connected Limited Device Configuration). Alle Geräte, für die eine Konfiguration eingesetzt wird, haben ähnlich charakteristische Eigenschaften, z.B. sehr geringe Speicherkapazität. Die CLDC 1.0 unterstützt keine Fließkomma­Operationen, dadurch bedingt ist das Schlüsselwort double aus dem Sprachumfang der Virtual­Machine ausgenommen. [Schm­2004],[Sun­2006]
6.3.2 Profiles
Die Profiles ergänzen die Konfiguration um einige High­Level APIs, die z.B. Zugriff auf gerätespezifische Eigenschaften erlauben oder Funktonalitäten zum erzeugen von User Interfaces bereitstellen. Eine beliebte Kombination bei Mobiltelefonen ist die CLDC Konfiguration mit dem MIDP Profil. Das Profil MIDP 2.0 setzt z.B. eine Displaygröße von mindestens 96x54 Pixel und 1 Bit Farbtiefe voraus. Als Eingabemethoden wird entweder ein Touchscreen oder eine Tastatur erwartet. [Schm­2004]
6.3.3 Optional packages Die optionalen Pakete erlauben es den Geräteherstellern Funktionalitäten hinzuzufügen, die auf ihr Gerät abgestimmt sind. Falls in einem Programm optionale Pakete verwendet werden, wird dessen Portabilität dadurch natürlich eingeschränkt. Ein solches optionales Paket wäre z.B. die Mobile Media API. [Sun­2006]
6.3.4 KVM
Die Kilobyte Virtual Machine (KVM), ist eine Virtual Machine, die vom Prinzip her vergleichbar mit der Java Virtual Machine ist. Der Unterschied liegt darin, dass die KVM sehr viel weniger Platz benötigt und geringere Ansprüche an den RAM stellt. Als Resultat davon fällt der Sprachumfang dementsprechend geringer aus. Dadurch, dass die KVM keine 98
Fließkomma­Zahlen und dementsprechend auch keine Fließkomma­Arithmetik kennt, fallen Funktionen zum Addieren, Subtrahieren, Multiplizieren, Dividieren, Konvertieren etc. von Float­ und Double­Werten weg. Des Weiteren verzichtet die KVM auf Java Native IO und streicht einige Teile der Exception Behandlung aus dem Sprachumfang, durch diese und weitere Einsparungen bedingt, gibt es einigen Bytecode nicht, den es aber im J2SE Sprachumfang gibt. Da man aber den gleichen Compiler (javac) benutzt, muss sichergestellt werden, dass in den “.class“­Dateien, welche den Java Bytecode enthalten, kein Code enthalten ist, den die KVM nicht kennt. In Handys kommt diese Kilobyte Virtual Machine anstelle der JVM zum Einsatz. 6.3.5 ByteCode­Verifikation
Die ByteCode­Verifikation findet bei J2ME Anwendungen in zwei Schritten statt. Die Java Virtual Machine hingegen erledigt diese Verifikation an einem Stück, zur Laufzeit. Die KVM kann nur preverifizierten Code ausführen. Bei der Preverifikation wird der ByteCode nach Code durchsucht, der nicht ablauffähig ist, da der Sprachumfang der KVM eingeschränkt ist. Des Weiteren fügt der Preverifikator Informationen in den ByteCode ein, der die Laufzeitverifikation erleichtern soll.
6.3.6 MIDlets entwickeln
Eine Applikation, die das Mobile Information Device Profile benutzt, nennt man MIDlet.
Um eine solche Applikation zu entwickeln ist ein Java Compiler nötig. Normalerweise wird der gleiche Compiler verwendet, der auch bei der J2SE Entwicklung genutzt wird. Aus diesem Grund ist es nötig, das Java SDK zu installieren. Es ist der Java Virtual Machine möglich, J2ME Programme zu starten, hierfür ist es aber nötig, dass man zusätzliche Bibliotheken hinzufügt, da Java 2 ME keine Untermenge von J2SE darstellt. Die zusätzlichen Bibliotheken und den Preverifikator bekommt man mit dem J2ME WirelessToolkit kostenlos von der Firma Sun Microsystems zum Download bereitgestellt.
99
6.4 WTK Das J2ME Wireless­Toolkit (WTK) stellt dem Softwareentwickler in Kombination mit dem Java 2 SE Software Development Kit (J2SDK) alle nötigen Programme zum Entwickeln von MIDlets. Die Kilobyte Virtual Mashine (KVM), der Preverifier, Klassenbibliotheken und Emulator sowie Paketierungs­Tool sind im WTK enthalten. Die Hersteller von Mobiltelefonen bieten meistens ein eigenes Toolkit an. Der Vorteil dieser Toolkits sind die Emulatoren, die besser auf das Handy abgestimmt sind; so auch das Siemens Mobility Toolkit (SMTK), das aber nur für Windows erhältlich ist. Mit WINE ist es möglich, das SMTK unter Linux laufen zu lassen. WINE ist ein Programm, dass es ermöglicht Windows Anwendungen auf Linux und Linux­ähnlichen Betriebssystemen auszuführen. Dabei ist es den Entwicklern wichtig, dass WINE nicht als Windows­Emulator bezeichnet wird, der Name WINE ist ein rekursives Akronym (Wine Is Not an Emulator), das genau dies zum Ausdruck bringt. Bei der Entwicklung von Java 2 ME Anwendungen habe ich das nativ unter Linux laufende WTK bevorzugt. Die Entwicklung unter Windows scheint beliebter zu sein, so gibt es das SMTK nicht für Linux und von dem WTK gibt es bereits eine Betaversion 2.5 für Windows; für Linux hingegen ist das WTK erst in der Version 2.2 verfügbar. Das WTK ist sehr übersichtlich gestaltet und ermöglicht direkt beim Anlegen eines Projekts eine schnelle Einstellung der zuvor beschriebenen Konfigurationen, Profile und der optionalen Pakete, die die neue Anwendung verwenden soll (siehe Abb. 31). Das WTK lässt einen Editor für Quellcode vermissen. Die Quellcode Dateien müssen deshalb mit einem anderem Programm erstellt werden. KWrite unterstützt den Programmierer mit Syntax­
Highlighting von Java Quellcode, kann aber eine richtige Entwicklungsumgebung nicht Abbildung 31: Projekteinstellungen für J2ME Projekte
ersetzen. Da dieser fehlende Editor bereits mehreren 100
Programmierern aufgefallen ist, gibt es z.B. das EclipseME Projekt (http://eclipseme.org). Es dieses ermöglicht J2ME Anwendungen unter Eclipse zu erstellen und den Emulator des WTK's aus der Eclipse­Oberfläche heraus zu starten. Ebenso lässt sich das J2ME Wireless Toolkit der Firma Sun Microsystems (WTK) in den JBuilder von Borland und in den JDeveloper der Firma Oracle integrieren. Die Möglichkeiten des Speicher­
Monitorings (Abb. 33 u. 32) erweitern das WTK um ein nützliches Tool.
Die Oberfläche des WTKs verbirgt die unterliegenden Programme, wie z.B. das Programm preverify, mit dem der Programmierer deshalb nicht in Kontakt kommt. Die Konsolenaufrufe des Programms enthalten Pfade zu Klassen und Informationen über den verwendeten Sprachumfang, so bedeutet der Abbildung 32: Memory Monitor Graph
Parameter ­nofp z.B., dass keine Fließkommazahlen und auch keine Fließkomma­Arithmetik verwendet werden darf. Abbildung 33: Memory Monitor Objects
101
6.5 Grafik
Für die Programmierung von GUI's bietet Java2 Micro Edition zwei Möglichkeiten. Eine High­, die andere Low­Level. Bei der Low­Level Variante zeichnet der Programmierer seine Grafik­Elemente selbst. Bei der High­Level Variante reiht er nur noch die Grafik­Elemente aneinander. Der Nachteil der High­Level Variante ist, dass die Grafik­Elemente bei verschiedenen Handys sehr unterschiedlich dargestellt werden (siehe Abb. 34 u. 35). Dies kann aber auch als ein Vorteil angesehen werden, denn der Handy­Hersteller kennt die Displaygröße und geht beim Zeichnen auf die gerätespezifischen Merkmale ein. Ebenso hat der Programmierer bei der High­Level Variante sehr wenig Einfluss auf die Anordnung der Softkeys. Es kann z.B. vorkommen, dass bei ein und dem selben Programm die Softkeys auf verschiedenen Handys unterschiedlich angeordnet sind.
Folgende Zeile erzeugt einen neuen Befehl, der mittels Softkey aufgerufen werden kann. private Command backCmd
= new Command("Back", Command.EXIT, 3);
Amp_Form.addCommand(backCmd);
Die untere der beiden Zeilen fügt diesen Befehl einer Form zu. Ob nun der rechte oder linke Softkey für das Kommando zuständig ist, ist aus beiden Zeilen nicht ersichtlich. Das Handy mit seiner KVM entscheidet darüber, welcher Button für diesen Befehl genutzt wird. Der erste Parameter ist das anzuzeigende Label für den Softkey, der zweite Übergabeparameter „Command.EXIT“, teilt den Typ des Kommandos mit. Anhand des Typs wird entschieden, auf welcher Seite der Softkey angezeigt wird. Wenn bei allen anderen Programmen der rechte Softkey zum Beenden da ist, wird dieser Softkey hier genauso angeordnet. Der Programmierer muss sich nicht einmal darum kümmern, wie viele Softkeys bereitstehen. Falls mehr Kommandos zu einer Form hinzugefügt werden, als Keys vorhanden sind, wird automatisch eine Liste von Befehlen angezeigt. Bei dem Siemens S65 wird ein Softkeys des Typs EXIT nach rechts verlegt. Handelt es sich um das einzige Kommando, so kann dieses auch durch Drücken des Joysticks betätigt werden. Die Gegenüberstellung der gleichen Applikation auf einem Handy und einer Simulation in Abb. 35 u. 34 zeigt, dass das Aussehen der Widgets sowie die Anordnung der Softkeys bei dem gleichen Programm unterschiedlich ist. Bei der Simulation ist der Softkey mit dem Back­Label links angeordnet, während er beim Siemens­S65 rechts bzw. in der Mitte (Joystick) ist.
102
Abbildung 35: High­Level Applikation auf Siemens S65
Abbildung 34: J2ME Simulation
Da der Programmierer sich bei der High­Level Programmierung kaum noch Gedanken um die Anordnung der Softkeys etc. machen muss, ist es möglich, kleine Programme zu schreiben, die nicht einmal eine DIN A4 Seite an Quellcode in herkömmlicher Schriftgröße benötigen. Alle J2ME Applikationen müssen von der Klasse MIDlet abgeleitet werden, da die “startApp()“­Methode dieser Klasse als Einstiegspunkt dient, vergleichbar mit der “main“­Funktion bei der C++ Programmierung. Des Weiteren ist es nötig die Methoden zur Lebenszyklus­Steuerung zu reimplementieren, da im Falle eines Telefonanrufs, während dem eine Applikation ausgeführt wird, diese durch die Funktion “pauseApp()“ von der KVM unterbrochen werden soll. Auf der nachfolgenden Seite ist das Programm angeführt, welches in Abb. 34 und 35 zu sehen ist. 103
/*
* InCarMultimedia (D10/034)
* Hochschule Darmstadt ­ university of applied sciences
* Rmote J2ME HMI © by Stefan Jaeger, 2006
*/
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class InCarMultimedia extends MIDlet implements CommandListener {
private Command backCmd = new Command("Back", Command.EXIT, 3);
public Display disp;
private Form Amp_Form;
//...
private static Gauge G_Volume;
private static Gauge G_Treble;
private static Gauge G_Bass;
private static Gauge G_Fader;
private static Gauge G_Balance;
public InCarMultimedia() {
//Display beschaffen
disp=Display.getDisplay(this);
Amp_Form = new Form("Settings");
G_Volume = new Gauge("Volume",true,5,1);
G_Bass = new Gauge("Bass",true,5,1);
G_Treble = new Gauge("Treble",true,5,1);
G_Balance = new Gauge("Balance",true,5,1); G_Fader = new Gauge("Fader",true,5,1);
Amp_Form.addCommand(backCmd);
Amp_Form.setCommandListener(this);
Amp_Form.append(G_Volume);
Amp_Form.append(G_Bass);
Amp_Form.append(G_Treble);
Amp_Form.append(G_Balance);
Amp_Form.append(G_Fader);
}
protected void destroyApp(boolean unconditional) {
}
protected void pauseApp() {
}
protected void startApp() {
//AmplifierForm anzeigen
disp.setCurrent(Amp_Form);
}
public void commandAction(Command c, Displayable d) {
if ( c == backCmd ) {
destroyApp(false);
notifyDestroyed();
}
}//ende CommandAction
}//ende InCarMultimedia
Listing 13: Quellcode einer J2ME High­Level GUI Applikation
104
J2ME­Programme werden in zwei Dateien ausgeliefert, die eine ist eine Jad­Datei (Java Application Descriptor), welche Informationen über das eigentliche Programm enthält. Bei Applikationen, die man aus dem Internet lädt, ist in ihr auch der Link zum eigentlichen Programm enthalten. Die andere Datei ist eine Jar­Datei (Java Archive), die, wie der Name schon sagt, eine gepackte Datei ist. In der Datei stecken alle Resourcen wie z.B. Grafiken, die im Programm verwendet werden und sämtliche .class­Dateien.
MIDlet­1: InCarMultimedia, InCarMultimedia.png, InCarMultimedia
MIDlet­Jar­Size: 1406
MIDlet­Jar­URL: InCarMultimedia.jar
MIDlet­Name: InCarMultimedia
MIDlet­Vendor: Unknown
MIDlet­Version: 1.0
MicroEdition­Configuration: CLDC­1.0
MicroEdition­Profile: MIDP­2.0
Listing 14: Inhalt einer Jad­Datei
In der .jad­Datei sind Informationen über die Versionen von CLDC und MIDP hinterlegt. MIDP und CLDC stellen das Runtime Environment für J2ME­Applikationen dar. Programme, die die MIDP­API benutzen, nennt man MIDlets. Die verschiedenen Versionen von MIDP legen Mindestanforderungen an die Hardware fest. So erkennt man bereits an der Jad­Datei, ob eine Applikation lauffähig ist und kann sich dadurch einen Download ersparen. Um mit dem Handy unser InCarMultimedia­System fernsteuern zu können, ist es nötig, eine Verbindung herzustellen. Da das Handy kein WLan­Interface und die Targets keinen Infrarot­Empfänger haben, bleibt nur Bluetooth zur Kommunikation. In der jsr082­API ist alles Nötige für eine Verbindung vorhanden. Im Quellcode der Applikation sind einige Dateien zu importieren. Das Importieren in J2ME könnte man mit C++'s Includes vergleichen.
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
...
Listing 15: Einige Imports für Bluetooth unter J2ME
105
Durch die verschiedenen Abstraktionsschichten im Netzwerkbereich gibt es kaum Unterschiede beim Erstellen einer Socketverbindung. So sieht eine Client/Server­Verbindung mit Bluetooth ähnlich der Verbindung im ganz normalen LAN aus.
Bei der Adressierung werden anstelle der IP und des Ports die Bluetooth­Adressse und der Kanal benötigt. Im Netzwerk gibt es sogenannte “well known ports“, dies bedeutet, dass ein Dienst üblicherweise einen bestimmten Port nutzt. Das HTTP­Protokoll beispielsweise nutzt üblicherweise den Port 80. Bei Bluetooth­Geräten ist dies nicht der Fall. Das Service Discovery Protocol (SDP) hilft herauszufinden, welche Dienste sich hinter welchem Kanal verbergen. Abbildung 36 und 37 zeigen die Dienste des Mobiltelefons und des InCarMultimedia­Systems an.
Abbildung 36: Bluetooth Dienste des Siemens­S65
Abbildung 37: Bluetooth Dienste des Target NG3
106
Auf der Konsole ist es mit der Applikation sdptool möglich die Bluetooth­Dienste erkennen zu lassen. sdptool browse XX:XX:XX:XX:XX:XX
...
Service Name: OBEX Synchronisation
Service RecHandle: 0x11104
Service Class ID List:
"IrMC Sync" (0x1104)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 5
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding:
0x6a
base_offset: 0x100
Profile Descriptor List:
"IrMC Sync" (0x1104)
Version: 0x0100
Service Name: Voice gateway
Service RecHandle: 0x11112
Service Class ID List:
"Headset Audio Gateway" (0x1112)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 2
Language Base Attr List:
code_ISO639: 0x656e
encoding:
0x6a
base_offset: 0x100
Profile Descriptor List:
"Headset" (0x1108)
Version: 0x0100
Service Name: Voice gateway
Service RecHandle: 0x1111f
Service Class ID List:
"Handfree Audio Gateway" (0x111f)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 3
Language Base Attr List:
code_ISO639: 0x656e
encoding:
0x6a
base_offset: 0x100
Profile Descriptor List:
"Handsfree" (0x111e)
Version: 0x0101
...
Listing 16: Bluetooth­Dienste des S65 ausgelesen mit sdptool
107
Um eine Schnittstelle zur Kommunikation bereitzustellen, könnte man einen “Remote­
Control­Service“ für das InCarMultimedia­System anbieten. Es nicht zwingend nötig dem SDP­Server mitzuteilen, dass dieser Dienst existiert. Um jedoch Dienste dynamisch auffindbar zu machen, ist es von Vorteil. Über das Radio Frequency Communication Protokoll (RFCOMM­Protokoll) ist es möglich eine SocketVerbindung aufzubauen oder ein TTY­Device zu emulieren. Dieses Protokoll setzt auf dem L2CAP (Logical Link Control and Adaptation Protocol) auf. Das L2CAP Protokoll bietet:
●
Komplette Abstraktion von HCI­Layer
●
Dienstgüte / Quality of Service ●
Verbindungslose Socket Schnittstelle ( SOCK_DGRAM )
●
Verbindungsorientierte Socket Schnittstelle (SOCK_SEQPACKED) Durch die Abstraktionsebenen erkennt der Programmierer kaum noch Unterschiede bei der Programmierung. Für die Programmierung einer Bluetooth Socket Verbindung sind zusätzlich einige Header nötig. #include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
Das Erzeugen eines Sockets ist hier gegenübergestellt. sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
sock = socket(AF_INET, SOCK_STREAM, 0);
Ebenfalls kleine Unterschiede gibt es bei der Zuweisung der Adresse, da die Bluetooth­
Adresse einen anderen Aufbau besitzt.
str2ba("XX:XX:XX:XX:XX:XX", &addr.rc_bdaddr);
inet_aton("XXX.XXX.XXX.XXX", &addr.sin_addr);
Ebenso gibt es keine Ports, sondern Kanäle.
addr.rc_channel = 1; addr.sin_port = htons(2000);
Der Aufruf bind, connect und close sind in bei einer herkömmlichen Netzwerkverbindung und der Bluetooth­Verbindung identisch. 108
Für eine Bluetooth­Verbindung unter QNX, ist es nötig, dass ein geeigneter Bluetooth­
Protokoll­Stack für dieses Betriebssystem vorhanden ist, oder portiert wird. Leider war es mir zeitlich nicht mehr möglich nach Treibern und geeignetem Protokoll­Stack zu recherchieren. Unter Linux gibt es einige Bluetooth­Protokoll­Stacks wie z.B. der OpenBT von AXIS oder der Affix Bluetooth­Stack von Nokia oder meinen persönlichen Favoriten, den Qualcomm BlueZ, die als Beispiel dienen könnten.
Die J2ME Programmierung wurde aus zeitlichen Gründen nicht weiter verfolgt und endet an dieser Stelle.
109
7 Irrwege
Am Anfang des Projektes hatte ich einige Probleme mit der Crosstoolchain. Das in arm­
linuxc++filt erläuterte mangling führt dazu, dass Symbole nicht gefunden werden, da verschiedene Compiler­Versionen eine unterschiedliche Art des manglings benutzen.
Die Libraries von Qt­Embedded waren zwar mit dem gleichen Compiler, jedoch in einer anderen Version erstellt worden.
Mit der nächsten Crosstoolchain kamen Fehler auf, da sie fest für die Verwendung mit Softfloat konfiguriert war. Die Fehlermeldung lautete arm­linux/bin/ld: ERROR: /home/shunter/ipaq/opt/QtPalmtop/lib/libqte.so uses hardware FP, whereas InCarMultimedia uses software FP
Ich werde kurz darauf eingehen was Hardware und Software FP ist, damit das Problem etwas verständlicher wird. Hardware FP besagt, dass Floating­Point Operationen in Hardware ausgeführt werden. Software FP benutzt eine in Assembler geschriebene Bibliothek, die speziell dafür entwickelt wurde, Floating­Point Operationen schnellstmöglich ohne Floating­
Point­Unit durchzuführen. Besitzt ein Prozessor keine Floating­Point­Unit, ist es so dennoch möglich Hardware FP zu nutzen. Die CPU wirft hierbei eine Exception, da ein ihr unbekannter Befehl untergekommen ist. Der Kernel reagiert auf die Exception und errechnet das Ergebnis in Software. Falls keine FPU vorhanden ist, dann ist aufgrund der hohen Kosten für die Ausnahmebehandlung die Hardware FP­Berechnung die langsamste der drei Möglichkeiten. Die Übergabe von Floating­Point­Werten geschieht bei den unterschiedlichen Verfahren auf andere Weisen, so ist der Compiler immer gezwungen das erzeugte Binary seiner c­lib anzugleichen. Durch die Verwendung eines anderem Cross­Compiler, war es möglich diesen Fehler zu umgehen.
Weitere solche kleinen Fehler brachten das Projekt in der Anfangsphase ins Stocken. Die im Anhang erläuterten Programme erwiesen sich bei der Auffindung solcher Fehler als hilfreich.
110
8 Anhang
8.1 Crosstoolchain
Eine Crosstoolchain ist eine Sammlung an Programmen, die für das Entwickeln von Software für eine andere Plattform benötigt wird. Unter anderem ist ein Crosscompiler Bestandteil einer Crosstoolchain. Aber der Compiler ist nur ein Tool von vielen. Es gibt mehrere Gründe dafür eine Crosstoolchain zu verwenden. ●
Nicht jedes Zielsystem verfügt über eine Tastatur zum Eintippen des Quellcodes. ●
Die Displays der Zielsysteme sind mit der Darstellung von Entwicklungsumgebungen überfordert.
●
Durch die meist knappen Resourcen dauert der Compiliervorgang auf den Targets wesentlich länger.
Im Folgenden werden kurz einige Programme, die zu der Toolchain gehören und verwendet wurden, vorgestellt. Ein großer Bestandteil der Crosstoolchain sind die sogenannten GNU­
Binutils. Diese sind eine Sammlung von Binär­Programmen, zu denen der GNU­Linker (ld) und der GNU­Assembler (as) gehören. Der Linker und der Assembler sind hiervon die bekanntesten, aber die Binutils­Sammlung enthält weitere Programme wie addr2line, ar, readelf, size, objcopy, strings, strip, runlib, objdump, nm, etc.. Bei einer Crosstoolchain sind die Programme meist nach ihrer Zielarchitektur benannt. Wenn man z.B. Programme für einen Arm­Prozessor entwickelt, und das Betriebssystem der Ziel­Architektur Linux ist, haben die Programme den Prefix „arm­linux­“. Der Linker bekommt dann den Namen „arm­
linux­ld“. Oftmals behalten die Programme auch ihren Namen, und es wird eine Verknüpfung mit dem Prefix „arm­linix­“ auf die Programme angelegt. Falls das verwendete Betriebssystem QNX ist, würde der Prefix „arm­qnx­“ heißen. Wenn man eine Entwicklungsumgebung wie Eclipse oder KDevelop benutzt, werden viele dieser Tools verwendet. Die Ausgaben werden in Fenster geschrieben, und es ist mit Mausklicks möglich z.B. Haltepunkte für den Debugger zu setzen. Dies erleichtert die Handhabung mit den Programmen ungemein, führt aber auch dazu, dass die Programmierer einiges verlernen. Wie man nach Symbolen in Object­Dateinen sucht, falls ein Symbol nicht aufgelöst werden 111
kann, stellt oftmals eine riesige Hürde dar. Aus diesem Grund sei ein grober Überblick über einige kleine aber doch sehr wichtige Programme gegeben.
8.1.1 arm­linux­readelf
Das Programm readelf zeigt Informationen über Binär­Dateien an, die im ELF­Format vorliegen. Das Executable and Linking Format (ELF) ist das übliche Format für Binärdaten unter Linux. Mit den Aufrufparametern, kann man die Informationen, die man einsehen möchte, bestimmen. Mit dem Parameter „­h“ bekommt man nur Informationen über den Header der ELF­Datei, die man als weiteren Parameter angeben kann. Mit dem Parameter „­H“ bekommt man die Hilfe angezeigt, die dann auf die anderen Parameter eingeht. Da die Hilfe recht gut ist wird hier auf eine Erläuterung aller Parameter verzichtet.
8.1.2 arm­linux­addr2line
Dieses Programm setzt Adressen in Dateinamen und Zeilennummer um. Als Parameter werden die Adresse und eine ausführbare Datei (Programm) benötigt. Es ist wichtig zu wissen, dass dies nur mit Programmen, bei denen die Debug­Informationen enthalten sind, funktioniert.
8.1.3 arm­linux­ar
Dieses Tool verwaltet Archiv­Dateien, welche typischerweise die Endung „.a“ tragen. Eine Archiv­Datei besteht aus beliebigen Dateien, die zu einer Archiv­Datei zusammengefasst werden. Die Dateien werden dabei nicht komprimiert. Hauptsächlich wird ar zur Verwaltung von Bibliotheken verwendet, obwohl es jegliche Art von Dateien verwalten kann. Damit der Linker mit Hilfe von ar die benötigten Bibliothek­Dateien zusammen linken kann, benötigt er die Symboltabelle der enthaltenen Objektdateien, diese Symboltabellen findet er in der Datei __.SYMDEF. Mit der Option ­s veranlasst man ar, diese Datei zu erstellen bzw. zu aktualisieren. Weitere Parameter ermöglichen es neue Dateien zum Archiv hinzuzufügen oder zu entfernen und vieles mehr. Da das Programm aus anderen Programmen, wie dem 112
Linker, heraus aufgerufen wird, muss man über das Programm selbst kaum Bescheid wissen. 8.1.4 arm­linux­ranlib
Ranlib macht das gleiche wie ar ­s und wird daher nicht näher beleuchtet.
8.1.5 arm­linux­nm
Das Programm nm listet Symbole, die in den übergebenen Object­Dateien enthalten sind, auf. Mit den verschiedensten Optionen, kann man die Aufbereitung der angezeigten Daten beeinflussen. Man kann z.B die enthaltenen Symbole nach verschiedenen Kriterien sortieren.
8.1.6 arm­linux­size
Dieses kleine Werkzeug gibt die Größe der verschiedenen Sektionen (.text, .data, .bss) einer oder mehrerer Object­Dateien aus. Das .text­Segment wird auch Code­Segment genannt, es beinhaltet den Programmcode und man kann nur lesend darauf zugreifen. Das .data­ und .bss­Segment enthält globale und statische Variablen. Auf diese beiden Segmente kann sowohl lesend als auch schreibend zugegriffen werden.
8.1.7 arm­linux­cpp
Das Programm cpp ist der C­Preprozessor. Er ist für die Ersetzung von Macros zuständig. Das Programm eignet sich für C, C++ und Objective­C Quellcode. Es wird vom Compiler, vor dem eigentlichen Compilier­Vorgang, aufgerufen und man kommt mit diesem Programm eigentlich nicht in Berührung. (nicht mit arm­linux­gcc verwechseln)
8.1.8 arm­linux­strings
Dieses Werkzeug extrahiert, bzw. gibt die enthaltenen Strings von Dateien aus. Es geht dabei 113
so vor, dass es nach 4 oder mehr zeichenbaren Buchstaben in einer Datei sucht, die von einem nicht zeichenbaren Charakter gefolgt sind. Mit Hilfe dieses Programmes kann man ausführbare Dateien z.B. nach Treiberaufrufen untersuchen, indem man in der Ausgabe von strings nach „/dev/...“ schaut. Bei Fehlern ist es also sehr hilfreich. 8.1.9 arm­linux­gdb
Dies ist der Debugger, er arbeitet als Konsolen­Applikation. Mit ihm ist es möglich das Binary Schritt für Schritt zu durchlaufen, Variablen­Inhalte anzuzeigen und vieles mehr. Aus Bequemlichkeit wird er meist in Kombination mit grafischen Frontends verwendet. 8.1.10 arm­linux­objcopy
Wie der Name der Applikation schon verrät, ist es dazu da, um Object­Files zu kopieren. Beim Kopieren des Inhalts der Object­Datei kann das verwendete Format über die Parameter bestimmt werden.
8.1.11 arm­linux­gcov
Mit diesem Programm kann man herausfinden, wie häufig Stellen im Code durchlaufen werden und somit z.B. Programmzweige auffinden, die vielleicht nicht durchlaufen werden können. Ein Beispiel wäre eine if­Anweisung, bei der man anstelle eines logischen Oders ein logisches Und verwendet hat.
if ( a<0 && a>100 ) cout<<"out of range"<<endl;
Syntaxfehler sind die Fehler einfachster Natur und werden bereits vom Compiler gefunden, Fehler in der Logik einer Applikation hingegen sind sehr viel schwerer zu finden und werden gerne überlesen. Das obere Beispiel ist ein Logikfehler, der dazu führt, dass einige Zeilen Code gar nicht ausgeführt werden. Ein noch beliebterer Fehler ist eine Zuweisung anstelle einer Gleichheits­Abfrage.
if (a=100) cout<<"Fertig!"<<endl; Häufig kommt dieser Fehler bei Leuten vor, die mit verschiedenen Programmiersprachen 114
hantieren. In Turbo Pascal ist := eine Zuweisung und = der Vergleichsoperator bei C++ hingegen ist = der Zuweisungsoperator und == der Vergleichsoperator. Dieses Beispiel wäre eine Anweisung, die immer ausgeführt wird. 0% oder 100% sollten bei if­Anweisungen also immer ein Warnhinweis sein. Das Programm gcov rundet seine Ausgaben normalerweise; eine Ausnahme hierbei ist 0 und 100 Prozent. 0% bedeutet, dass die Zeile kein einziges mal und 100% bedeutet, dass die Zeile auch wirklich immer ausgeführt wurde. 8.1.12 arm­linux­as
Der GNU­Assembler ist ein Assembler, für verschiedene Prozessoren oder besser gesagt, der GNU­as stellt eine Assembler­Familie dar. Beim arm­linux­as, handelt es sich um den GNU­
Assembler, der für die Benutzung für arm­Prozessoren konfiguriert wurde.
8.1.13 arm­linux­objdump
Das Programm objdump zeigt verschiedenste Informationen über Object­Files an.
8.1.14 arm­linux­strip
Strip wird dazu genutzt um Symbole aus Object­Dateien oder Archiven also statischen Bibliotheken zu entfernen. Auf Embedded Geräten ist strip sehr sinnvoll, da die Dateien wesentlich kleiner werden.
Mit der Option –strip­debug, enfernt man alle Debug­Symbole. Das Debuggen wird hierdurch nahezu unmöglich aber die Datei wird um einiges kleiner.
8.1.15 arm­linux­ld
Der Linker wird am Ende eines Kompiliervorgangs aufgerufen, er linkt die Object­Dateien und Archive zu Ausführbaren­Dateien zusammen und löst somit die Symbole auf. Im Falle des Remote­HMI­Projektes, das man für X86 und arm­Prozesooren übersetzten 115
kann, ist es wichtig, dass man bevor man für eine andere Plattform den Übersetztungsprozess abstößt, die bereits erstellten Object­Files löscht, indem man „make clean“ aufruft. Make ist es egal, für welche Plattform gebaut wird. Es übersetzt ein Target nur dann neu, wenn die Dateien, von denen das Target abhängig ist, neuer als das Target selbst sind. Ändert sich an einigen Quellen nichts, so werden die unveränderten Quellen nicht neu kompiliert und der Linker versucht im Falle, dass man die Zielarchitektur ändert, arm und x86 Object­Files zusammen zu linken. Eine sehr wichtige Option des Linkers ist die Option ­L, mit der man einen Pfad angeben kann, in dem der Linker nach Bibliotheken sucht. Im Falle, dass man für mehrere Plattformen baut, sind diese Bibliotheken in verschiedenen Ordnern, sodass man nur den Suchordner neu angeben muss.
8.1.16 arm­linux­c++filt
Höhere Programmiersprachen wie C++ und Java ermöglichen die Funktionsüberladung. Dies ermöglicht Funktionen mit gleichem Namen, aber unterschiedlichen Übergabeparametern zu implementieren. z.B.
double InCarMultimedia(bool a)
{
if (a)
return 3.14;
return 9.81;
}
double InCarMultimedia(double a, double b)
{
return a+b;
}
int InCarMultimedia (int a, int b)
{
return a+b;
}
Auf Assembler Ebene müssen die Funktionsnamen eindeutig sein, das Encodieren zu eindeutigen Namen, die also auch die Parameter berücksichtigen, nennt man „mangling“.
c++filt decodiert (demangled) diese Namen wieder, sodass sie wieder vom Benutzer gelesen 116
werden können. [c++filt­2006] Mit readelf ist es möglich die Symoble zu lesen. Sie setzen sich aus Funktionsnamen und Parameter zusammen. Die oben angeführten Funktionen werden zu den Symbolen _Z15InCarMultimediab, _Z15InCarMultimediadd und _Z15InCarMultimediaii.Das sogenannte mangling ist vom Compiler abhängig. In diesem Fall wurde der gcc in der version 4.0.3 zum kompilieren herangezogen.
8.1.17 Crosscompiler Ein Crosscompiler ist ein Compiler, der auf einer Plattform läuft und ausführbare Dateien (Binaries) für eine andere Plattform produziert. In unserem Beispiel wird auf einem x86 Prozessor entwickelt und es werden Programme erzeugt, die auf einem XSCALE Prozessor laufen. Die Prozessoren haben unterschiedliche Befehlssätze, sie sind nicht miteinander kompatibel. Ein Crosscompiler setzt also den Quellcode (in unserem Fall sei dies C++) in Maschinencode einer anderen Prozessor­Architektur um.
Den Gnu Compiler kann man so konfigurieren, dass er zum Crosscompiler wird.
Dazu ruft man das beiliegende „configure“­Script auf und übergibt die nötigen Parameter.
Mit dem Parameter –target teilt man dem Gnu Compiler mit, für welche Zielplattform er Maschinencode erzeugen soll. Mit dem Parameter –host kann man angeben, auf welcher Plattform der Crosscompiler selbst lauffähig sein soll, also auf welcher Plattform entwickelt wird. Der –built Parameter gibt an, von welcher Plattform der Compiler selbst kompiliert wird.
117
9 Fazit
Das Anbinden mehrerer HMI's an das InCarMultimedia­Framwork, ist, wie in der Arbeit dargestellt, möglich. Ohne ein Konzept wäre dies nur schwer realisierbar. Das Konzept hat sich umfangreicher entwickelt, als zu Anfang erwartet. Der neu eingefügte AudioMaster muss viele Dinge berücksichtigen, beispielsweise das dynamische An­ und Abmelden der Remote­HMIs und die Resourcenvergabe beliebig vieler Geräte.
Die konkrete Implementierung der Remote­HMI gestaltete sich schwierig und damit zeitaufwändiger als vorgesehen, da es ein Ziel war, die vom zentralen Audiomaster vorgesehene Rechteverwaltung zu berücksichtigen und die Bedienmöglichkeiten dementsprechend einzuschränken.
Die Softwareentwicklung für einen XScale­Prozessor erwies sich als denkbar einfach, sobald die Entwicklungsumgebung einmal fertig konfiguriert war. Doch dies sollte nicht unterschätzt werden. Es empfiehlt sich daher nach einer geeigneten Entwicklungsumgebung Ausschau zu halten. Der Einstieg in die GUI­Programmierung mit Qt war für mich Neuland. Im Laufe des Projektes erwies sich Qt als einfaches und schnell zu erlernendes GUI­Toolkit und dementsprechend als die richtige Wahl.
Bei dieser Arbeit lagen die Prioritäten nicht darin, alle Komponenten bis ins Detail fertig zu implementieren. Es war wichtiger aufzuzeigen, wie man eine Remote­HMI gestalten könnte und welche Änderungen dies am Framework mit sich ziehen würde. Der aufgezeigte Weg ist nur eine von vielen Möglichkeiten, einen AudioMaster und eine Remote­HMI zu implementieren. Der so gestaltete AudioMaster passt gut ins vorgegebene Framework und erlaubt es die geforderten Aufgaben zu erledigen und bietet eine leichte Möglichkeit zur Erweiterung.
118
10 Zusammenfassung
Mit dieser Arbeit wurde ein Konzept erstellt, das es ermöglicht, mehrere HMIs an einem InCarMultimedia­System zu betreiben. Hierzu war es nötig, weitere Komponenten in das Framework einzufügen. Der in das Framework neu eingefügte AudioMaster regelt über Prioritäten, welche HMIs über welche Devices steuerbefugt sind. Der AudioMaster ist so konzipiert, dass er bei Erweiterungen des Frameworks um weitere HMIs nicht verändert werden muss. Das Framework wurde so erweitert, dass es mit mehreren Verstärkern zurecht kommt. Der AudioMaster unterstützt ebenfalls eine beliebige Anzahl von Verstärkern und Abspielgeräten. Das Framework wurde um eine „WlanServer“­Komponente erweitert, die eine Verbindung über Socket ermöglicht. Somit ist es möglich, das Framework aus der Ferne zu bedienen. Eine weitere HMI wurde entwickelt, die über diesen WLanServer mit dem Framework verbunden ist. Die neue HMI ist auf Linux PC's und dem HP­iPAQ h5500 lauffähig und erlaubt es, das Framwork von den Rücksitzen des Autos aus zu steuern. Schließlich wurde ein Menü einer weiteren HMI für Mobiltelefone entwickelt, und darauf eingegangen, wie eine Verbindung realisiert werden könnte.
119
11 Ausblick
Der Ausblick enthält einerseits Dinge, die zeitlich bedingt nicht implementiert wurden und andererseits verrät dieser Blick in die Zukunft, was man noch erweitern könnte.
11.1 Handy
Die Remote­HMI für Handys ist weitaus interessanter, als die des PDA's je sein könnte, betrachtet man nur einmal die Verbreitung des Handy in der Bevölkerung dazu im Vergleich.
Die HMI könnte in J2ME sowohl mit der vorgestellten High­Level als auch Low­Level Grafik programmiert werden. Für die Kommunikation ist es jedoch nötig, dass man geeignete Bluetooth­Treiber für QNX besitzt oder portiert. Des Weiteren ist es nötig, einen geeigneten Protokoll­Stack zu portieren, falls es diesen noch nicht gibt. Unter Linux gibt es mehrere, der wohl bekannteste ist der BlueZ. Mit ihm lässt sich problemlos eine Socket­
Verbindung erstellen.
Neuere Handys besitzen die Möglichkeit, einen Phyton­Interpreter nachzuinstallieren. Mit ihm ist es möglich, weitaus performantere Software zu erstellen, als es mit J2ME möglich ist. 11.2 AudioMaster
Der abstrakt gehaltene AudioMaster ermöglicht nicht nur die Einbindung von Verstärkern sondern es wäre ebenfalls denkbar, einen HD­Recoder an Stelle eines Verstärkers einzusetzen. Genauso gut ist es möglich, dass eine Navigations­Komponente sich anstelle einer HMI beim AudioMaster anmeldet und den TMC­Tuner für sich beansprucht, um so Staumeldungen über TMC zu erhalten. Die Möglichkeiten sind hier recht offen gehalten. Die Funktion REGISTER_HMI ist also nicht nur auf HMI's beschränkt und müsste deshalb eigentlich einen anderen Namen bekommen; REGISTER_REQUESTOR oder ähnliches wäre denkbar.
120
11.3 Lokale HMI
Die lokalen HMI's verarbeiten im aktuellen Software Stand des Frameworks die GOT_CONTROL und LOST_CONTROL Nachrichten nicht. Dies sollte sich in Zukunft noch ändern. Bei der Arbeit wurde dies hinten angestellt, da die lokalen HMIs ohnehin die höchste Priorität besitzen und somit automatisch die Kontrolle über die angeforderten Devices bekommen. Im Falle, dass LOST_CONTROL Nachrichten empfangen werden, müssten Buttons ausgeblendet oder ausgegraut werden, so wie es bei der Remote­HMI bereits der Fall ist.
11.4 Software­Paket
Wie im Abschnitt zur Software Auslieferung bereits erwähnt, sollte das Remote­Projekt als Paket verpackt werden, das dann mit dem Paket­Manager der jeweiligen Distribution ausgeliefert werden kann. Somit ist es nicht nur Informatiker vorbehalten, sich das Paket zu installieren.
11.5 Plattformunabhängigkeit
Es sollte angestrebt werden, das remote InCarMultimedia­Project auch unter Windows PDAs lauffähig zu machen, da die Mehrzahl der PDA's nicht mit Linux ausgeliefert wird. Die momentane Version ist nur unter Linux lauffähig. Um für Windows kompatibel zu werden, müssten die Threads und die Socket­Verbindung überarbeitet werden. Mit diesen kleinen Änderungen sollte es möglich sein, durch erneutes Kompilieren auch eine Windows Version bereit zu stellen.
121
12 Danksagung
Die schöne aber auch anstrengende Zeit des Studierens ist fast verstrichen. Ein Dankeschön an alle diejenigen, die mich auf diesem Abschnitt meines Lebens begleiteten. Simon Kretschmer, Bettina Kurz, Michael Müller, Manfred Pester und Sergio Vergata waren für mich in dieser Zeit mehr als nur Kommilitonen und Laboringenieure. Sie standen mir immer tatkräftig zur Seite, halfen mir, wo sie nur konnten und verschönerten so mein Studium.
Bei meinem Referenten Prof. Dr. Joachim Wietzke und meinem Korreferenten Prof. Dr. Ralf Hahn möchte ich mich für das spannende Thema der Masterarbeit bedanken.
Ein ganz großes Dankeschön an Stefan Eich, der Teile meiner Arbeit ins Deutsche übersetzte. Ebenso herzlich möchte ich mich bei Ingeborg Gasser und Svenja Weber für die Korrekturen bedanken. Allen anderen Korrekturlesern und Leserinnen gilt ebenfalls ein herzliches Dankeschön.
Als kleiner Junge war ich fasziniert vom Schachspielen, denn es war das einzige Spiel, bei dem ein Bauer sich aussuchen konnte, was aus ihm einmal wird; sofern er je die andere Seite des Spielfeldes erreichen würde.
Mit ca. zwölf Jahren hörte ich mit dem Schachspielen auf. Doch meine Begeisterung für dieses Spiel ist bis heute nicht erloschen. Weitere zwölf Jahre später wurde mir erst bewusst, dass ich nie auf gehört hatte dieses Spiel zu spielen. Ich hatte nur das Brett verlassen.
Nun bin ich an dem Punkt angelangt, die andere Seite des Spielfeldes zu erreichen. Und möchte mich bei den beiden Leuten bedanken, die mir dieses Spiel ermöglichten. Danke Mammi und Pappi!
122
Index
A
gdb.....................................................114
addr2line............................................112
GOT_CONTROL........................46, 121
ar........................................................112
GPE.....................................................60
as........................................................115
GTK+..................................................60
B
H
Betriebssystem....................................57
Hardware FP......................................110
Bootloader...........................................61
I
C
InCarMultimedia­Systeme..................22
c++filt................................................116
InstanceID...........................................21
CONNECT..........................................46
iPAQ....................................................24
cpp.....................................................113
IPKG...................................................95
Crosstoolchain...................................111
J
D
Jad.....................................................105
Datencontainer....................................35
Jar......................................................105
demangle...........................................116
Java......................................................96
DeviceID.............................................20
Java2 Micro Edition..........................102
Distribution.........................................57
JBuilder.............................................101
E
JDeveloper.........................................101
EclipseME.........................................101
K
Emulator............................................100
Komponente........................................18
Exception...........................................110
L
F
ld........................................................115
Familiar...............................................61
Linux...................................................96
Firmware.............................................61
LOST_CONTROL......................46, 121
Floating­Point­Unit............................110
M
Framework...........................................17
MainDispatcher...................................18
FunctionBlockID.................................20
mangling............................................116
FunctionID..........................................21
Meta­Object­Compiler........................65
G
MOST..................................................19
gcov...................................................114
N
123
nm......................................................113
size.....................................................113
O
SMTK................................................100
objdump.............................................115
Softkey..............................................102
Opie.....................................................59
Software FP.......................................110
Optype.................................................21
SSH.....................................................95
OS­Abstraction­Layer.........................96
strings................................................113
P
strip....................................................115
PalmOS...............................................96
SymbianOS.........................................96
PDA.....................................................57
T
Prioritätssystem...................................37
Target...................................................17
Q
U
QPixmaps,...........................................68
Übergangstabelle.................................37
QPushButton.......................................68
User­Interface­Compiler.....................65
Qt Palmtop Environment.....................59
W
Qt­Embedded......................................58
Widget.................................................60
QTopia.................................................59
WINE................................................100
R
WTK ................................................100
ranlib..................................................113
X
readelf................................................112
X11......................................................58
REGISER_SOURCE..........................46
Xlib.....................................................58
REGISTER_DESTINATION.............46
.
REGISTER_HMI..............................120
.bss.....................................................113
REGISTER_REQUESTOR..............120
.data...................................................113
S
.desktop...............................................94
Siemens S65........................................24
.text....................................................113
Siemens­S65......................................102
.ui..................................................65, 89
124
Literaturverzeichnis
[WiTr­2005] Wietzke, Joachim; Tran, Manh Tien
Automotive Embedded Systeme : Berlin Heidelberg : Springer, 2005 [Kurz­2005]
Kurz, Bettina
Transp. Segm. v. Nachr. z. Einb. e. Apple­IPOD i. e. MOST­Framew., 2005
http://www.fbi.h­da.de/fileadmin/personal/j.wietzke/ ...
... mein_ordner/Studentenarbeiten/IPOD_im_MOST_Framework.pdf
Zuletzt besucht am: 07.09.2006 um 15:58 Uhr
[Drex­2006]
Drexler, Michael
Siemens­S65
http://www.Siemens­S65.de/
Zuletzt besucht am: 25.09.2006 um 13:55 Uhr
[hp­2006]
Hewlett­Packard Development Company, L.P.
Grafik
http://www.hp.com/hpinfo/newsroom/press_kits/2003/ipaq/
Zuletzt besucht am: 19.08.2006 um 15:15 Uhr
[qnx­2006]
QNX Software Systems
Grafik
http://www.qnx.com/images/products/adv_graphics/graphics_device.gif
Zuletzt besucht am: 16.08.2006 um 11:29 Uhr
[lugod­2006] Linux Users' Group of Davis
Grafik
http://www.lugod.org/presentations/zaurus­talk/pics/qtopia_02.png
Zuletzt besucht am: 24.08.2006 um 10:25 Uhr
[Hand­2006] Handhelds.org
Open Source Operating Systems for Handheld Devices
www.handhelds.org
Zuletzt besucht am: 28.09.2006 um 18:48 Uhr
125
[Troll­2006]
Trolltech
Online Reference Documentation
http://doc.trolltech.com/
Zuletzt besucht am: 07.09.2006 um 17:45 Uhr
[Blan­2004]
Blanchette, Jasmin; Summerfield, Mark
C++ : GUI­Programmierung mit Qt3
München : Addison­Wesley, 2004 [Schm­2004] Schmatz, Klaus­Dieter
Java 2 Micro Edition : Entw. mobiler Anwendungen mit CLDC und MIDP
Heidelberg : dpunkt.verlag GmbH, 2004 [Sun­2006]
Sun Microsystems, Inc.
Java ME Technologies
http://java.sun.com/javame/technologies/index.jsp#1
Zuletzt besucht am: 15.09.2006 um 17:42 Uhr
[c++filt­2006] Free Software Foundation, Inc.
Manual Page c++filt, 2006
Packet: binutils­2.16.91
126

Documentos relacionados