Hochschule Darmstadt Entwurf und
Transcrição
Hochschule Darmstadt Entwurf und
Hochschule Darmstadt Fachbereich Informatik Entwurf und Implementierung eines MultiHMI Konzeptes Zur Anbindung von Mobile/RemoteHMIs an ein InCarMultimediaSystem 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 MultimediaSysteme 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 RearSeatEntertainment. Im Rahmen dieser Arbeit wurden diese Fähigkeiten in das an der Hochschule entwickelte MultimediaFramework eingebunden. Es wurden Konzepte für die verschiedenen Problemstellungen entwickelt. Neben der Kommunikation zwischen der RemoteHMI und dem MultimediaSystem zeigt sich die Notwendigkeit eines durchdachten Konzeptes zur prioritätsgesteuerten Rechte und Ressourcenvergabe. Durch die Realisierung einer dazu bestimmten SoftwareKomponente 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 RemoteHMI 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 ReferenzImplementierung für weiterführende RemoteAnwendungen 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 EntertainmentFeatures concurrently with other passengers, named as RearSeatEntertainment is the mainsubject of this thesis. The needed features have been integrated into the given multimediaframework 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 HMIunits 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 LinuxPDA, 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 (HumanMashineInterface)........................................................................18 2.2 MOST..........................................................................................................................19 2.3 Verwendete Hardware.................................................................................................22 2.3.1 InCarMultimediaSysteme...................................................................................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 HPiPAQ h5500............................................................................................24 2.3.2.2 Siemens S65 Mobiltelefon...........................................................................24 3 Konzept...............................................................................................................................25 3.1 Framework im Ausgangszustand.................................................................................25 3.2 Das InCarMultimediaSystem im Wandel...................................................................26 3.2.1 Die Unterbringung der Verwaltung in einer RemoteHMI..................................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 MOSTTreiber..............................................................................................34 3.2.4.4 Ist und SollDatencontainer........................................................................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 DatenKapselung..................................................................................................41 3.2.5.4 Umschaltlogik..............................................................................................42 3.2.6 Anbindung der RemoteHMI...............................................................................42 3.2.7 UpdateEvents und DatenContainer......................................................................43 3.3 RemoteHMI als MOSTDevice..................................................................................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 HPiPAQ 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 / QtEmbedded............................................................................................58 5.2.2 Opie.....................................................................................................................59 5.2.3 OTopia / QPE .....................................................................................................59 5.2.4 GPE ....................................................................................................................60 5.2.5 GTK+ vs. QtEmbedded......................................................................................60 5.3 Ein neues Betriebssystem auf den PDA spielen..........................................................61 5.4 Qt/QtEmbedded..........................................................................................................61 7 5.4.1 SignalSlot...........................................................................................................62 5.5 Designer......................................................................................................................64 5.6 UIC UserInterfaceCompiler...................................................................................65 5.7 MOC MetaObjectCompiler....................................................................................65 5.8 QtAssistant.................................................................................................................65 5.9 Remote HMI als HighLevelKomponente.................................................................66 5.9.1 Der DisableButton...............................................................................................68 5.9.1.1 Die MyPicKlasse........................................................................................69 5.10 Das Hilfsprogramm Converter...................................................................................71 5.10.1 Vom ButtonClick 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 HPiPAQ 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 KUIViewer................................................................................................................89 5.19 RemoteHMI in Qt.....................................................................................................91 5.20 Icon für den PDADesktop 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 ByteCodeVerifikation.........................................................................................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 armlinuxreadelf................................................................................................112 8.1.2 armlinuxaddr2line............................................................................................112 8.1.3 armlinuxar........................................................................................................112 8.1.4 armlinuxranlib.................................................................................................113 8.1.5 armlinuxnm......................................................................................................113 8.1.6 armlinuxsize.....................................................................................................113 8.1.7 armlinuxcpp.....................................................................................................113 8.1.8 armlinuxstrings................................................................................................113 8.1.9 armlinuxgdb.....................................................................................................114 8.1.10 armlinuxobjcopy.............................................................................................114 8.1.11 armlinuxgcov..................................................................................................114 8.1.12 armlinuxas......................................................................................................115 8.1.13 armlinuxobjdump...........................................................................................115 8.1.14 armlinuxstrip..................................................................................................115 8.1.15 armlinuxld......................................................................................................115 8.1.16 armlinuxc++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 SoftwarePaket.........................................................................................................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 FloatingPointUnit GPE GPE Palmtop Environment GUI Graphical User Interface HCI Host Controller Interface HMI Human Mashine Interface ICM InCarMultimedia 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: MOSTDevices..................................................................................................20 Abbildung 2: InCarMultimediaSystem (Target PON)...........................................................22 Abbildung 3: InCarMultimediaSystem (Target NG3)............................................................23 Abbildung 4: HPiPAQ h5500 (Pocket PC) aus [hp2006].................................................24 Abbildung 5: S65 (aus [Drex2006])......................................................................................24 Abbildung 6: AudioMaster zur Ressourcen Verwaltung.........................................................30 Abbildung 7: MostProxy Inheritance Graph...........................................................................32 Abbildung 8: Anbindung der RemoteHMI an das Framework..............................................42 Abbildung 9: LOST_CONTROL............................................................................................47 Abbildung 10: GOT_CONTROL............................................................................................47 Abbildung 11: Interaktion mit dem AudioMaster (Sequenzdiagramm)..................................50 Abbildung 12: DisplaySizes...................................................................................................52 Abbildung 13: QNX's Grafik Abstraktionen angelehnt an [qnx2006]...................................54 Abbildung 14: MiniCom.........................................................................................................55 Abbildung 15: MainMenu.......................................................................................................55 Abbildung 16: TunerMenu......................................................................................................55 Abbildung 17: MiniComSimulator........................................................................................56 Abbildung 18: MaxiComSimulator.......................................................................................56 Abbildung 19: QTopia PDA Edition (aus [lugod2006])......................................................59 Abbildung 20: GPE (aus [Hand2006])..................................................................................60 Abbildung 21: Verbinden von Signalen mit Slots im Designer..............................................64 Abbildung 22: SignalSlot Verbindungen...............................................................................64 Abbildung 23: Aufbau der CMessage.....................................................................................66 Abbildung 24: Forken bei KonsolenApplikationen...............................................................82 Abbildung 25: BarWidget 40%..............................................................................................85 Abbildung 26: BarWidget 70%..............................................................................................86 Abbildung 27: BarWidget 40% mMiddleBar=false...............................................................86 Abbildung 28: verschiedene Qt Styles in KUIViewer............................................................90 Abbildung 29: ScreenShot Opie (GamesTab) .......................................................................94 Abbildung 30: J2ME & J2SE im Vergleich (angelehnt an [Schm2004])..............................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: HighLevel Applikation auf Siemens S65.....................................................103 Abbildung 36: Bluetooth Dienste des SiemensS65.............................................................106 Abbildung 37: Bluetooth Dienste des Target NG3................................................................106 13 Tabellenverzeichnis Tabelle 1: FunctionBlockID der MOSTDevices....................................................................21 Tabelle 2: In der Entwicklung stehende HMIs........................................................................26 Tabelle 3: Connection Registry...............................................................................................38 Tabelle 4: Registry nicht normalisiert.....................................................................................39 Tabelle 5: HMITabelle...........................................................................................................39 Tabelle 6: DestinationTabelle.................................................................................................40 Tabelle 7: SourceTabelle........................................................................................................40 Tabelle 8: RegistryTabelle......................................................................................................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: HeaderDatei Bar.h.................................................................................................87 Listing 8: Styleangaben für QtProgramme............................................................................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 HighLevel GUI Applikation.........................................104 Listing 14: Inhalt einer JadDatei..........................................................................................105 Listing 15: Einige Imports für Bluetooth unter J2ME...........................................................105 Listing 16: BluetoothDienste 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 AudioVisuelle Anlagen, halten ihren Einzug in das Automobil. In einem InCarMultimediaSystem 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 InCarMultimediaSystem zu betreiben, um später eine oder mehrere RemoteHMIs verwenden zu können. In unserem Fall soll die RemoteHMI 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 EmbeddedBereich entwickelt man die Software aus Bequemlichkeit meist am PC und überträgt die fertige Software dann auf das ZielSystem; dieses ist die Hardware, auf dem die fertige Software eingesetzt werden soll. Das ZielSystem 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, ObjektDateien zu erzeugen und aus ObjektDateien Binaries. Die ObjektDateien sind also ZwischenZiele und das Binary das EndZiel. Im Englischen spricht man von SubTarget 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 InCarMultimediaFramework im einzelnen ankommt, kann in [WiTr2005] S.13 ff nachgelesen werden. 17 2.1.3 Komponente Das verwendete InCarMultimediaFramework besteht aus verschiedenen Komponenten. Diese Komponenten sind SoftwareModule, die unabhängig gestartet, überwacht, beendet und gegebenenfalls neu gestartet werden können. Die AdminKomponente 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 TunerKomponente, diese bildet den Tuner in unserem Framwork ab. Gleiches ist für den CDPlayer, 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 InCarMultimediaSystems, 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 (HumanMashineInterface) Die MenschMaschineSchnittstelle (engl. HMI) des InCarMultimediaSystems 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 HMIKomponente ist die zentrale Steuereinheit des InCarMultimediaSystems. 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 HMIKomponente ist im Folgenden auch als HMI bezeichnet. Anhand des Kontextes ist die verwendete Form (Hardware / Software) unterscheidbar. 2.2 MOST Der MOSTBus ist ein Bus zur Kommunikation zwischen verschiedenen Geräten und kann jede Art von Daten übertragen. So werden z.B. Audiodaten vom CDSpieler 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 SampleRate von CDs, damit ist die Musikwiedergabe von CDs ohne Pufferung möglich. Die Frames sind in einen synchronen, asynchronen und einen KontrollKanal 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 MOSTGerä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 RingTopologie 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: MOSTDevices 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 MOSTDevices 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 MOSTSpezifikation 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 MOSTNachricht 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 MOSTNachricht bezieht sich nur auf die Größe der Daten, da die restliche Größe ohnehin bekannt ist. [WiTr2005], [Kurz2005] 21 2.3 Verwendete Hardware 2.3.1 InCarMultimediaSysteme Die in dieser Arbeit verwendeten InCarMultimediaSysteme der Firma Harman/Becker bestehen aus MOSTGeräten (Verstärker, CDPlayer, iPod, Tuner, ...) und der HMI, die ein LCDDisplay zur Visualisierung und ein Eingabegerät zur Steuerung besitzt. Außerdem verfügt dieses System über eine Festplatte, FlashSpeicher, RAM, NetzwerkInterface und weiteren HardwareKomponenten. 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 MOSTBus gut erkennen. Alle MOSTGeräte sind in einer RingTopologie angeordnet und mit zweien dieser Kabel verbunden, eines zum Empfangen und eines zum Senden der Daten. Oben in der Mitte des Bildes (zwischen den MOSTLeitungen) befindet sich eine Adapterplatine, die den Apple iPod Abbildung 2: InCarMultimediaSystem (Target PON) zu einem MOTGerät werden lässt. 22 2.3.1.2 Target NG3 Dieses Target verfügt über einen Renesas Hitachi SuperH 4 Prozessor (SH4) mit 400 MHz, eine Realtek 100 MBit Netzwerkkarte, eine Grafikkarte mit CoralChip, der sowohl 2D als auch 3DFunktionen unterstützt. Außerdem besitzt dieses Target einen zweiten Prozessor (ST10), der mit dem seriell angeschlossenen Bedienteil und dem MOSTBus 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 DVDPlayer löst den CDPlayer, der in dem älteren PONTarget ist, ab. Abbildung 3: InCarMultimediaSystem (Target NG3) 23 2.3.2 Remote Geräte 2.3.2.1 HPiPAQ h5500 Der HPiPAQ h5500 ist ein Persönlicher Digitaler Assistent (PDA), der, mit dem mitgelieferten Betriebssystem MS Pocket PC 2003 und PIM Tools eine gut ausgereifte SoftwareBasis 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 SDSpeicherkarten etc. wird nicht Abbildung 4: HPiPAQ h5500 (Pocket PC) aus [hp2006] 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 JAVAFä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 [Drex2006]) 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 InCarMultimediaFramework sind etliche Komponenten vorhanden. Alle Komponenten laufen als unterschiedliche Prozesse, die über Queues miteinander kommunizieren. Die Queues sind im SharedMemory 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 MOSTGeräte wie den Tuner abbilden, sind in einen Controller, ein LogDev und einen Proxy unterteilt. Der Proxy eines MOSTGerätes bildet dessen Funktionalitäten ab. Falls beispielsweise ein CDSpieler 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 MOSTGeräte nicht möglich, alle theoretisch denkbaren Aktionen auszuführen, so könnte es z.B. sein, dass es einen CDSpieler gibt, der im PlayModus keine CDs auswerfen kann. Der Controller verhindert mit seiner StateMachine, in solche nicht erlaubten Zustände zu wechseln. Das InCarMultimediaSystem besitzt in der Ausgangssituation einen CDSpieler, einen iPod, einen Tuner und einen Verstärker, die als MOSTGeräte an der HeadUnit angeschlossen sind. Die HeadUnit ist die HauptPlatine, an der das Bedienteil und ein LCDDisplay angeschlossen sind. Softwareseitig gibt es eine HMIKomponente, 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 MOSTTreiber, der die MOSTNachrichten über den Bus versendet hat eine feste Zuordnung von FunctionBlockID und DeviceID's, da alle TargetSysteme gleich aufgebaut sind. 25 3.2 Das InCarMultimediaSystem 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 TargetTypen 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 TargetNG3 Photon Minicom sh4 QNX TargetPON Qt/Embedded Pen XScale Linux HPiPAQ (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 MOSTBus vorhandene Verstärker soll für die AutoLautsprecher zuständig sein, der zweite für den Kopfhörerausgang im Rücksitz Bereich. Die vorhandenen Abspielgeräte, wie z.B. der Tuner, der CDPlayer 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 KomponentenID 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 RemoteHMI Die Rechtebeschränkung bzw. die Regelung der Steuerbefugnis kann man auf keinen Fall in einer der RemoteHMIs unterbringen, da diese nicht zwangsweise mit dem Target verbunden sind. Wenn man die Regelung der Rechte in einer RemoteHMI unterbringen könnte, hätte man den Vorteil, dass man am Framework nur minimale Änderungen vornehmen müsste. Die RemoteHMI 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 RemoteHMI ist auf TargetSeite eine Komponente vorgesehen, die alle Nachrichten der RemoteHMI 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 TargetTypen das Programm erstellt wird, wird eine der beiden lokalen HMIs beim Übersetzungsvorgang nicht berücksichtigt. Wenn man den VerwaltungsCode nur in eine der beiden HMIs stecken würde, dann gäbe es bei dem anderen Target keine Verwaltung. Dieser VerwaltungsCode 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 RemoteHMI 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 RemoteHMIs 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 SaintExupéry Dieser Satz von Antoine de SaintExupé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. StateMachine 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 HMIController 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 AudioGerä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 LogischeDevice (kurz LogDev) gleich bleiben und nur der Proxy, der den Stellvertreter für das physikalische Gerät darstellt, neu geschrieben werden muss. Auf MOSTSeite 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 CAmpMostProxyKlasse abgeleitet, welche den Standard MOSTKatalog als Implementierungsgrundlage verwendet (siehe Abb. 7). Diese Klasse ist wiederum von der CMostProxyBaseKlasse abgeleitet, welche die grundlegenden Gemeinsamkeiten aller MOSTGeräte enthält. Dazu gehört das Decodieren von einzelnen Datentypen etc.. Die Abweichungen vom StandardMOSTKatalog werden in den jeweiligen Proxies durch Reimplementieren der betroffenen Funktionen der CAmoMostProxyKlasse 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 MOSTRing vorhanden ist, ist bei den Targets PON und NG3 unterschiedlich, dadurch ist eine Unterscheidung im Framework nötig. Die Proxies sind nach den TargetSystemen 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 SoundEinstellungen 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 AdminKomponente, in der die beiden AmplifierKomponenten 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 CDPlayer oder der AppleiPod 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 TrackNr. beim CDPlayer 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 SoundEinstellungen 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 MOSTTreiber Der MOSTTreiber ist dafür zuständig, die MOSTNachrichten, die innerhalb des Framworks nur mit der FunctionBlockID und der InstanceID adressiert sind, an das richtige Gerät zu senden. Die Empfängeradresse der MOSTNachricht muss um das Feld DeviceID erweitert werden. Wenn man eine feste Konfiguration von MOSTGeräten im InCarMultimedia System hat, ist die Zuordnung sehr einfach. Man kann mit dem Mostolyzer (einem Analyse Gerät für MOSTBusse, die Daten betrachten, die über den Bus versendet werden. Hierdurch erfährt man, dass beispielsweise der CDPlayer 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 MOSTTreiber muss ebenfalls das neue Target NG3 unterstützen. Die oben genannte AnalyseMethode 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 MultiHMIKonzeptes wurden zusätzliche Verstärker an die Targets angeschlossen. An einigen Targets ist zusätzlich ein iPod oder ein CDWechsler hinzugefügt worden. Es gibt nun kaum noch Targets mit den gleichen MOSTGerä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 TargetTyp 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 MOSTLeitungen eine gewisse Reihenfolge eingehalten würde, so stünden die DeviceIDs zu Compilezeit fest. Falls ein Kunde nachträglich einen CDWechsler eingebaut haben möchte, kann er dies nicht selbstständig durchführen, da ein SoftwareUpdate nötig wäre. In dem vorhandenen InCarMultimediaFramework werden die Komponenten immer mit aufgenommen. 34 Die IPodKomponente ist immer ein fester Bestandteil der Software, auch wenn kein iPod am Target angeschlossen ist. Eine zweite VerstärkerKomponente 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 MOSTRing 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 MOSTGeräte ist diese auf äquivalente Weise realisiert. 3.2.4.4 Ist und SollDatencontainer Der IstDatencontainer hält die gerade aktuellen Informationen eines Gerätes. Dieser gehört zum Gerät. Beim Beispiel eines CDChangers ist im DatenContainer vermerkt, welche CD und welches Lied gerade spielt. Ein SollDatenContainer hingegen gibt vor, welche CD und welches Lied gespielt werden soll. Als es bisher nur eine HMI gab, entschied man das der 35 SollDatencontainer 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 CDMenü. 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 CDChanger und andere Geräte. Wenn man sich dieses Szenario anschaut und weitere UmschaltSzenarien durchspielt, wird man zum Ergebnis kommen, dass jede HMI ihren eigenen SollDatenContainer 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 RemoteHMI bei der Vergabe vom KopfhörerVerstä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. RemoteHMIs bekommen eine geringere Priorität als die lokalen HMIs. Denn die RemoteGeräte sollen in Konfliktfällen benachteiligt behandelt werden. Am konkreten Beispiel würde dies bedeuten, dass derjenige, der das InCarMultimediaSystem 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 HighLevelEvent in Form einer ApplicationMessage, 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 HarddiskRecorder für Audiodaten implementieren. Dieser könnte Telefongespräche mitschneiden, Radiosender aufzeichnen oder CDInhalte 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. UpdateNachrichten könnten so gezielt an die jeweiligen HMIs versendet werden. Beispiel: Die TunerKomponente versendet Radiotext, weiß aber nicht, an welche HMIs sie die UpdateNachricht senden soll. Eine Möglichkeit wäre, diese UpdateNachricht an den AudioMaster zu leiten. Dieser vermerkt sich, welche HMI sich gerade im TunerMenü befindet und sendet den Radiotext gezielt an diese Komponente weiter. Die UpdateNachricht eines CDPlayer, 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 UpdateNachrichten auf dieses Weise zu versenden, da es der HMI auch möglich sein soll im CDMenü 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 KanalListe 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: HMITabelle 39 ID Destination ID der steuerbefugten HMI 0 Amp3 0 1 Amp1 0 2 Amp2 1 Tabelle 6: DestinationTabelle 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: SourceTabelle HMIID SourceID DestinationID 0 0 1 1 0 2 0 1 0 Tabelle 8: RegistryTabelle 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 KomponentenID der HMI und deren Priorität. Die IDSpalte 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 VTable besitzt. In unserem Fall wäre jedoch keine virtuelle Klasse nötig. 40 Geschwindigkeit Die Zugriffe über Set und GetMethoden sind langsamer als der direkte Zugriff auf einen Struct. Public Deklarationen der Membervariablen erlauben ebenfalls die gleiche Zugriffsgeschwindigkeit. DatenKapselung 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 GetterMethoden 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 RegistryTabelle 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 MemberVariablen, 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 HMITabelle 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 TMCTuner 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 RemoteHMI Die RemoteHMI 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 RemoteHMI 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 RemoteHMI im InCarMultimediaFramework. Über eine Socketverbindung ist der HPiPAQ an das InCarMultimediaFramework angeschlossen. Da die RemoteHMI als HighLevelKomponente fungieren soll, schickt sie die Befehle als 42 ApplicationMesssages 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 RemoteHMI versendet werden sollen, müssen als ReceiverID die “wLanServerID“ eingetragen haben. Alle Nachrichten, die der HPiPAQ versendet sind mit “wLanServerID" im Absender markiert. 3.2.7 UpdateEvents und DatenContainer Auf TargetSeite 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 MOSTParser aus dem MOSTKatalog generieren lassen, der den Datencontainer automatisch füllt siehe [WiTr2005]. Die RemoteHMI kann nicht auf den Datencontainer zugreifen, da der Datencontainer im SharedMemory auf der TargetSeite liegt. Bei jedem UpdateEvent den DatenContainer zu streamen wäre nicht sehr sinnvoll, wenn man bedenkt, dass z.B. auf den AppleiPod 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 UpdateEvent 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 RemoteHMI bekommt ein UpdateEvent, kann aber nichts damit anfangen, weil sie keinen Zugriff auf den Datencontainer hat. Die WLanServerKomponente, die die Remote HMI auf TargetSeite „vertritt“, hätte Zugriff auf den Datencontainer. Die RemoteHMI muss also der WLanServerKomponente mitteilen, dass sie Teile des Datencontainers streamen soll. Bisher war die WLanServerKomponente nur dafür da, Nachrichten, die in ihrer Queue 43 angekommen sind, über Socket an den HPiPAQ 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 RemoteHMI verschickt werden und danach müsste die RemoteHMI 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 UpdateNachricht den aktuellen Wert unterzubringen. Somit könnte man die WLanServerKomponente einfach halten und eine hohe Performance erzielen. Das HighLevelEvent 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 UpdateNachricht nicht genügend Platz ist, um beispielsweise die komplette TrackListe des iPods zu übertragen. Da sich weder die TrackListe des iPods noch die TrackListe einer CD ständig ändern, sind hier Geschwindigkeitseinbußen unkritisch. Eine andere Möglichkeit wäre es, MOSTNachrichten von Abspielgeräten direkt an die RemoteHMI weiter zu leiten. Dafür müsste eine RemoteHMI MOSTNachrichten verstehen können. 44 3.3 RemoteHMI als MOSTDevice Es bestünde die Möglichkeit, die RemoteHMI direkt als MOSTDevice zu gestalten. Sie würde dann anstelle der HighLevelEvents über das MOSTProtokoll kommunizieren. An dieser Stelle ist es sinnvoll darüber nachzudenken, warum die lokale HMI mit HighLevel Events kommuniziert. Was waren die Gründe dafür, dass man dieses zusätzliche Protokoll eingeführt hatte? Die HighLevelEvents entsprechen den Bedientasten. Falls ein CDPlayer den Befehl Scan nicht kennt, soll dieser trotzdem als HighLevelEvent an die CDPlayerKomponente verschickt werden können. Die Komponente ist dann dafür zuständig, dass sie das High LevelEvent Scan in mehrere MOSTNachrichten verwandelt und somit das Scan nachbildet. Die Umsetzung eines Scans könnte wie folgt aussehen. Play ( 10 sekunden warten ) > NextTrack > ( 10 sekunden warten ), .... vergleiche [WiTr2005]. Für den HMIProgrammierer ist es ebenfalls eine wesentliche Erleichterung, wenn er alle Geräte mit den gleichen HighLevelEvents ansprechen kann, ohne darauf achten zu müssen, ob die Geräte die Befehle überhaupt kennen. Falls man die RemoteHMI direkt als MOSTDevice ansprechen wollte, dann würde man sicher auf RemoteHMI 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 MOSTProxies würden wahrscheinlich wieder zum Dekodieren der MOSTNachrichten verwendet werden. Die MOSTProxies bieten nach oben ein einheitliche Schnittstelle, obwohl sie auf MOST Seite unterschiedliche Nachrichten versenden. Das LogischeDevice 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 LogischeDevice 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 RemoteHMI Seite zu implementieren, sondern gleich in Form von HighLevelEvents mit der RemoteHMI 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 SourceDevices genannt werden. Theoretisch soll es auch ermöglicht werden, dass sich eine Komponente anmeldet, die beispielsweise AudioDaten auf Festplatte aufnimmt. Sie würde ebenfalls den Opcode REGISTER_DESTINATION verwenden. Ein FestplattenRecorder 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 HighLevel 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 KomnponentenIDs 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 RemoteHMI nur die Steuererlaubnis für den Verstärker. Wechselt die HMI mit höherer Priorität in das CDMenü, 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 MOSTBus. 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 DestinationDevices. Die im Sequenzdiagramm mit HMI 2 betitelte HMI ist eine RemoteHMI, 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 TunerMenü ausgewählt. Die HMIKomponente 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 HMI1TunerAmp1 und die Verbindung HMI2iPodAmp2 hinterlegt. Zu jedem Source und DestinationDevice 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 HMIListe aus. Danach durchsucht er die Registry nach Einträgen, die die zweite HMI betreffen. Die Verbindung HMI2iPodAmp2 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 iPodKomponente 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 KomponentenID 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 InCarMultimediaSystems und der dazu nötigen Konzepte. Es wäre praktisch, wenn man für die RemoteGeräte und die InCarMultimediaSysteme 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 DisplayGrößen der unterschiedlichen HMIs. Nachfolgende Grafik zeigt die Displaygrößen der verwendeten Geräte in Pixel an. Abbildung 12: DisplaySizes 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 DisplayHöhe von 52 480 Pixeln müsste laut Pixelverhältnis fünf mal so hoch sein, wie Target PON mit einer DisplayHö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 HPiPAQ 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 CDMenü drei LiedTitel untereinander anzeigen lassen und im Target NG3 fünf oder sechs LiedTitel. 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 GFLib aufsetzt. Die GFLib 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 [qnx2006] 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 GrafikChip 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 DrehRad ü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 HPiPAQ besitzt außer dem Stift zum Steuern vier weitere Tasten, die man als Softkeys einsetzen könnte. Da der HPiPAQ 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 QNXx86 Plattform. Abbildung 17: MiniComSimulator Abbildung 18: MaxiComSimulator 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 MouseEvents bearbeiten werden. Möchte man den HPiPAQ 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 HPiPAQ 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 HPiPAQ h5500 Da der Entschluss getroffen wurde, keine gemeinsame Grafik zu erzeugen, ist es nötig, für die einzelnen RemoteGerä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 ProzessorArchitektur 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 PaketManager darüber, welche Distribution gewählt wird. Theoretisch könnte man nahezu jede Distribution seinen Wünschen anpassen, da Linux OpenSourceSoftware ist und demnach der Quellcode offen liegt. In unserem Fall sieht das Ganze etwas anders aus. Für den HPiPAQ ist eine sehr kleine Linux Distribution erforderlich, DesktopUmgebung 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 HPiPAQ 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 PaketManager wird Ipkg eingesetzt. Dieser ermöglicht es, unser RemoteProjekt in einer späteren Version als Paket auszuliefern. Ein SSHServer 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 DesktopDistributionen 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 PIMApplikationen 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 StandardSoftware für diese Oberfläche gibt. 5.2.1 QTE / QtEmbedded QtEmbedded ist die Embedded Version von Qt. Qt ist ein Grafik Framework, mit dem z.B. KDE programmiert wurde. QtEmbedded 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 OpenSourceProdukte entwickelt, ist QtEmbedded kostenlos. QtEmbdedded ist keine grafische Umgebung, sondern das unter einigen grafischen Oberflächen liegende GrafikFramework. 58 5.2.2 Opie Open Palmtop Integrated Environment Opie wird von keiner speziellen Firma oder Organisation entwickelt oder vertrieben. Opie wird stattdessen von SoftwareEntwicklern 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 [lugod2006]) MusikDateien. 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 DesktopUmgebung 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 [Hand2006]) 5.2.5 GTK+ vs. QtEmbedded 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 GrafikFramework 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 QtEmbedded 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 SignalSlotPrinzip 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 LizenzSystem ist die Entwicklung von nichtkommerzieller OpenSourceSoftware kostenlos, das macht sich das RemoteProjekt 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 WLanModul bereits installiert ist, da dieses Firmware Update nur für das original Betriebssystem vorhanden ist. Auf der oben genannten InternetSeite 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 LCDisplay nach dem Einschalten des Gerätes erst einmal dunkel. 5.4 Qt/QtEmbedded Eine Errungenschaft von Qt ist sein MetaObjectMechanismus, der zu Objekten Lauzeittypinformationen und Vererbungsinformationen etc. hinzufügt. Zu diesen Errungenschaften gehört auch der Signal/SlotMechanismus, 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 SignalSlot Eine Grundlage für Qt ist das SignalSlot 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 SignalSignal 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. SignalSignal Verbindungen unterscheiden sich nicht von SignalSlot 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 SignalSlot oder SignalSignal 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 OnlineDokumentation 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 MetaObjectCompiler 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 SignalSlot 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 SignalSlotPrinzip, wie es in Qt verwendet wird, ist eine synchrone Kommunikation, die an Prozessgrenzen gebunden ist. 63 5.5 Designer Der QtDesigner 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 QtDesigner 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 UserInterfaceDateien abgelegt. Abbildung 22: SignalSlot Verbindungen 64 5.6 UIC UserInterfaceCompiler Der UserInterfaceCompiler von Qt erzeugt aus .uiDateien, wie sie vom QtDesigner erstellt werden, C++Quelldateien und dazugehörige Header. Die .uiDateien liegen im XMLFormat vor und müssen erst gewandelt werden, bevor sie in den Kompiliervorgang integriert werden können. 5.7 MOC MetaObjectCompiler Der MetaObjectCompiler 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 QtAssistant Der QtAssistant ist eine Applikation, die bei der Dokumentation behilflich ist. Er enthält die OnlineDokumentation 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 HighLevelKomponente Das Konzept sieht vor, die Remote HMI als HighLevelKomponente zu gestalten, damit Abstraktionsschritte nicht mehrmals vollzogen werden müssen. Gerade für eine RemoteHMI wie z.B. ein Mobiltelefon ist möglichst alles was auch auf dem InCarMultimediaSystem 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 HighLevel 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 GetterMethoden für den Zugriff auf sämtliche Daten. HighLevelEvents werden in unserem Framework in sogenannten ApplicationMessages (AppMessage) versendet. Die ApplicationMessages bestehen in unserem Framework aus dem mType, dieser hilft bei der Feststellung, ob es sich um eine MOSTNachricht oder ein HighLevelEvent handelt. 66 Desweiteren besteht ein HighLevelEvent 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 HMIProjekt nötig, dass die Global.h und die CMessage.h immer mit dem Framework auf gleichem Stand gehalten werden. Die Daten des HighLevelEvents unterteilen sich in opcode und parameter14. 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 RemoteSeite ist kein MainDispatcher vorhanden, deshalb erzeugt man eine CMessage, setzt die Werte über die SetterMethoden der CMessage Klasse und versendet sie dann über Socket. ... msg.setSenderID(HMIID); msg.setReceiverID(Amp0ID); msg.setOpcode(VOLUME); ... Das HighLevelProtokoll ist sehr einfach gehalten und somit leicht erlernbar. Für den HP iPAQ wurde unter Qt ein Slot eingeführt, der das Setzen über SetterMethoden 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 RemoteHMI Projekt der Absender immer die RemoteHMI 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 OriginalFunktionen 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 MyPicKlasse 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 InitFunktion 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 HeaderDatei 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 cppDatei 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 HeaderDatei 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 KonsolenApplikation, 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 MyPicKlasse 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, VisualStudio ProjektDatein und das Makefile für Linux. 71 5.10.1 Vom ButtonClick 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 HPiPAQ 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 HandleClickedSlot 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 AmplifierKlasse sendet ein weiteres Signal aus, welches aus der ReceiverID, dem Opcode, und den Parametern 13 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 TargetSeite weiß, was sie mit der Lautstärke tun soll. Der Parameter2 gibt die Inkremente an. Dieses Signal wird mit einem Slot der WLanClientKlasse verbunden. Diese fügt als SenderID noch WLanServerID hinzu und generiert ein HighLevelEvent, 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 SenderTyps wird entschieden, welche weitere Verarbeitung geschieht. Eine ApplicationMessage, wie in unserem Framework die HighLevelEvents 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 Amp1Komponente angekommen, wird wieder anhand des SenderTyps entschieden, was mit der Nachricht zu tun ist. Hier wird unter Zuhilfenahme des Proxies eine MOSTMessage erstellt. Die MOSTNachricht wird dann dem MainDispatcher in die Queue gelegt, dieser erkennt anhand des SenderTyps, dass es sich diesmal um eine Nachricht für den MOSTBus handelt. Die Nachricht wird an den MOST TranceiverThread weitergeleitet, der Anhand des FunctionBlocks und der InstanceID weiß, zu welchem Device die MOSTNachricht gesendet werden muss. In unserem Falle ist dies beispielsweise das Device mit der ID 0x103. Der MOSTTranceiver schickt also die Nachricht über seinen MOSTTreiber 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 WLANServer zum MainDispatcher von hieraus zum Amplifier und wieder zurück zum MainDispatcher in den TranceiverThread. Allein auf dem InCarMultimediaSystem waren hierfür mehrere Prozess und ThreadSwitches nötig damit die Nachricht ihr Ziel erreicht. Dazu kommt noch die Verbindung zum HPiPAQ. Die Hälfte des Weges ist nun zurückgelegt. Jetzt muss die Information mit der neuen Lautstärke wieder zurück zum HPiPAQ ü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 [Troll2006] und dem Buch [Blan2004]. 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 trFunktion 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 QtLinguist .tsDateien zu bearbeiten und für die neue Sprache eine Übersetzung bereitzustellen. Die .tsDateien liegen im XMLFormat vor und können auch per Hand editiert werden. Mit dem Programm lrelease wird aus den „.ts“Dateien eine .qmDatei 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 ObjektDateien. 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 ProjektDatei 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 .qmDateien nach .tsDateien 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 localeFunktion 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 LoadBefehl versucht in diesem Fall zuerst die Datei “my_app_de_AT.ISO8859-15.qm“ zu laden. Existiert diese nicht, probiert der LoadBefehl die Datei “my_app_de_AT“ zu laden. Bis er schließlich mit der Datei “my_app_de.qm“ fündig wird. [Blan2004], [Troll2006] 77 5.12 TMAKE „tmake“ ist ein PerlScript, 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 ObjectCompiler verändert werden müssen, und der Aufruf des MetaObjectCompilers 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 QtProgrammen 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. ObjektDateien werden als SubTargets 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 HauptTarget ist meist das Binary, welches erstellt werden soll. Es hängt nicht von Quelldateien, sondern von ObjectDateien ab, die dann erst von den Quelldateien abhängig sind. Speziell bei Qt ist es so, dass die Quelldateien erst durch den MetaObjectCompiler verändert werden müssen, so dass selbst die ObjectDateien nicht direkt von den QuellDateien, 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 HPiPAQ generieren möchte, so weist man der Variablen CXX „armlinuxg++“ 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 „armlinuxg++ 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 HPiPAQ erzeugen Da man nicht für QtX11 in der Version 3.xx kompilieren möchte, die man auf seinem PC verwendet, sondern für QtEmbedded in der Version 2.xx, setzt man das QTDIR entsprechend dem Ordner, in dem man die Libraries und Header für den HPiPAQ gespeichert hat. Da der UserInterfaceCompiler und der MetaObjectCompiler 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 QtopiaVersionen von Trolltech werden SpezifikationsDateien 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 SpezifikationsDatei richtig gesetzt. Sie zeigt nun auf „armlinuxg++ DQT_QWS_IPAQ“. Damit dieser Compiler gefunden wird, muss noch der Pfad, in dem er sich befindet, zur PATHVariablen 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 HPiPAQ 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 BuildSkriptes 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 CompilerAufrufe erzeugten Prozesse kennen damit die gesetzten Variablen. Ansonsten gingen die gesetzten Umgebungsvariablen nach Beendigung des Kindprozesses verloren. Abbildung 24: Forken bei KonsolenApplikationen 82 5.16 Unterscheidung Qt/X11 und Qt/E Da das RemoteProjekt für DesktopRechner ebenso gültig sein soll wie für den HPiPAQ, 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 DesktopRechner 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 VollbildModus gestartet, während sie auf dem DesktopRechner in einem Fenster läuft. 84 5.17 Eigene Widgets Für viele Applikationen ist es ausreichend, die StandardWidgets 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 EventHandler für das Zeichnen und für die MausAktionen wie z.B. mouseMoveEvent und mousePressEvent reimplementiert. Unsere AnzeigeBar 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 AnzeigeModi. 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: BarWidget 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: BarWidget 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: BarWidget 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: HeaderDatei 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 LayoutManagern festzulegen. Für eine solche Bar ist in der YRichtung eine feste Größe (QSizePolicy::Fixed) sinnvoll und in XRichtung 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 XRichtung 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 QtDesigner eintragen, das gestaltet das Arbeiten im Designer genauso einfach wie mit Qt eigenen Widgets. Leider zeigt der QtDesigner 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 paintEventMethode 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 QuellcodeDatei Bar.cpp nachgelesen werden. 88 5.18 KUIViewer Wie die meisten Programme, die für KDE geschrieben wurden, fängt auch dieses Programm mit einem „K“ an. Der KUIViewer zeigt Dateien mit der Endung “.ui“ an, wie sie vom QtDesigner erstellt werden. Qt ist ein plattformübergreifendes GrafikFramework, das versucht, sich an das native Aussehen des Betriebssystems anzupassen. So sehen die gleichen QtWidgets unter Windows anders aus als unter Linux. Um das Aussehen eines QtProgramms zu ändern, kann man es mit der Option –style starten. ./InCarMultimedia –style=Windows Listing 8: Styleangaben für QtProgramme Weitere Styles sind: ● Motif ● CDE ● SGI ● Platinum ● MotifPlus ● Windows XP ● Mac Bei der Programmierung der eigenen Widgets wird diese StyleAngabe nicht beachtet, so dass das „Bar“Widget überall identisch aussieht. Das Programm KUIViewer kann die eigenen Widgets nicht darstellen, da in der UIDatei 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 SettingsTab der HMI in den Styles Default, Light, Platinum und Keramik. Da die aktuelle RemoteHMI zum Teil aus eigenen Widgets besteht, macht es wenig Sinn, diese mit dem KUIViewer anzuzeigen. Hier wird ein Stand zu Anfang des Projekts gezeigt. Abbildung 28: verschiedene Qt Styles in KUIViewer Die Styles Windows XP und Mac sind eine Ausnahme, sie basieren auf der DesignEngine der jeweiligen Plattform. 90 5.19 RemoteHMI in Qt In Qt ist es üblich mit dem SignalSlot Prinzip zu arbeiten. Wenn ein Button angeklickt wird, geschieht nur etwas, wenn das clickedSignal 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 HeaderDatei 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 BassEinstellung 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 SocketVerbindung 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 AmplifierKlasse 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 UpdateNachrichten werden von dem SlothandleAppMessage(cont Cmessage&) verarbeitet. Um beim Beispiel des Basses zu bleiben, wird dieser, wenn er in einer UpdateNachricht 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 SignalSlot 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 PDADesktop erstellen Auf PDAs sind DesktopIcons 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 (GamesTab) zum Starten der dort enthaltenen Programme. Um ein solches Icon zu erstellen legt man eine .desktopDatei 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 ICMIcon angezeigt wird. Der Games Ordner wurde gewählt, da er nicht so überfüllt ist und man so das ProgrammIcon 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 PaketManager 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 RemoteHMI für das SiemensS65 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 OperatingSystem einsetzen. Vereinzelte HandyHersteller 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 OSAbstractionLayer, 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 SetTop Boxen, VideoTelefonen, 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 [Schm2004]) 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. [Schm2004] 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ßkommaOperationen, dadurch bedingt ist das Schlüsselwort double aus dem Sprachumfang der VirtualMachine ausgenommen. [Schm2004],[Sun2006] 6.3.2 Profiles Die Profiles ergänzen die Konfiguration um einige HighLevel 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. [Schm2004] 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. [Sun2006] 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ßkommaZahlen und dementsprechend auch keine FließkommaArithmetik kennt, fallen Funktionen zum Addieren, Subtrahieren, Multiplizieren, Dividieren, Konvertieren etc. von Float und DoubleWerten 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 ByteCodeVerifikation Die ByteCodeVerifikation 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 WirelessToolkit (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 PaketierungsTool 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 WindowsEmulator 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 EclipseOberflä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ßkommaArithmetik 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 LowLevel. Bei der LowLevel Variante zeichnet der Programmierer seine GrafikElemente selbst. Bei der HighLevel Variante reiht er nur noch die GrafikElemente aneinander. Der Nachteil der HighLevel Variante ist, dass die GrafikElemente bei verschiedenen Handys sehr unterschiedlich dargestellt werden (siehe Abb. 34 u. 35). Dies kann aber auch als ein Vorteil angesehen werden, denn der HandyHersteller kennt die Displaygröße und geht beim Zeichnen auf die gerätespezifischen Merkmale ein. Ebenso hat der Programmierer bei der HighLevel 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 BackLabel links angeordnet, während er beim SiemensS65 rechts bzw. in der Mitte (Joystick) ist. 102 Abbildung 35: HighLevel Applikation auf Siemens S65 Abbildung 34: J2ME Simulation Da der Programmierer sich bei der HighLevel 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 LebenszyklusSteuerung 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 HighLevel GUI Applikation 104 J2MEProgramme werden in zwei Dateien ausgeliefert, die eine ist eine JadDatei (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 JarDatei (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 .classDateien. MIDlet1: InCarMultimedia, InCarMultimedia.png, InCarMultimedia MIDletJarSize: 1406 MIDletJarURL: InCarMultimedia.jar MIDletName: InCarMultimedia MIDletVendor: Unknown MIDletVersion: 1.0 MicroEditionConfiguration: CLDC1.0 MicroEditionProfile: MIDP2.0 Listing 14: Inhalt einer JadDatei In der .jadDatei sind Informationen über die Versionen von CLDC und MIDP hinterlegt. MIDP und CLDC stellen das Runtime Environment für J2MEApplikationen dar. Programme, die die MIDPAPI benutzen, nennt man MIDlets. Die verschiedenen Versionen von MIDP legen Mindestanforderungen an die Hardware fest. So erkennt man bereits an der JadDatei, ob eine Applikation lauffähig ist und kann sich dadurch einen Download ersparen. Um mit dem Handy unser InCarMultimediaSystem fernsteuern zu können, ist es nötig, eine Verbindung herzustellen. Da das Handy kein WLanInterface und die Targets keinen InfrarotEmpfänger haben, bleibt nur Bluetooth zur Kommunikation. In der jsr082API 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/ServerVerbindung mit Bluetooth ähnlich der Verbindung im ganz normalen LAN aus. Bei der Adressierung werden anstelle der IP und des Ports die BluetoothAdressse und der Kanal benötigt. Im Netzwerk gibt es sogenannte “well known ports“, dies bedeutet, dass ein Dienst üblicherweise einen bestimmten Port nutzt. Das HTTPProtokoll beispielsweise nutzt üblicherweise den Port 80. Bei BluetoothGerä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 InCarMultimediaSystems an. Abbildung 36: Bluetooth Dienste des SiemensS65 Abbildung 37: Bluetooth Dienste des Target NG3 106 Auf der Konsole ist es mit der Applikation sdptool möglich die BluetoothDienste 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: BluetoothDienste des S65 ausgelesen mit sdptool 107 Um eine Schnittstelle zur Kommunikation bereitzustellen, könnte man einen “Remote ControlService“ für das InCarMultimediaSystem anbieten. Es nicht zwingend nötig dem SDPServer mitzuteilen, dass dieser Dienst existiert. Um jedoch Dienste dynamisch auffindbar zu machen, ist es von Vorteil. Über das Radio Frequency Communication Protokoll (RFCOMMProtokoll) ist es möglich eine SocketVerbindung aufzubauen oder ein TTYDevice zu emulieren. Dieses Protokoll setzt auf dem L2CAP (Logical Link Control and Adaptation Protocol) auf. Das L2CAP Protokoll bietet: ● Komplette Abstraktion von HCILayer ● 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 BluetoothVerbindung identisch. 108 Für eine BluetoothVerbindung unter QNX, ist es nötig, dass ein geeigneter Bluetooth ProtokollStack für dieses Betriebssystem vorhanden ist, oder portiert wird. Leider war es mir zeitlich nicht mehr möglich nach Treibern und geeignetem ProtokollStack zu recherchieren. Unter Linux gibt es einige BluetoothProtokollStacks wie z.B. der OpenBT von AXIS oder der Affix BluetoothStack 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 CompilerVersionen eine unterschiedliche Art des manglings benutzen. Die Libraries von QtEmbedded 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 armlinux/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 FloatingPoint Operationen in Hardware ausgeführt werden. Software FP benutzt eine in Assembler geschriebene Bibliothek, die speziell dafür entwickelt wurde, FloatingPoint Operationen schnellstmöglich ohne Floating PointUnit durchzuführen. Besitzt ein Prozessor keine FloatingPointUnit, 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 FPBerechnung die langsamste der drei Möglichkeiten. Die Übergabe von FloatingPointWerten geschieht bei den unterschiedlichen Verfahren auf andere Weisen, so ist der Compiler immer gezwungen das erzeugte Binary seiner clib anzugleichen. Durch die Verwendung eines anderem CrossCompiler, 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ärProgrammen, zu denen der GNULinker (ld) und der GNUAssembler (as) gehören. Der Linker und der Assembler sind hiervon die bekanntesten, aber die BinutilsSammlung 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 ArmProzessor entwickelt, und das Betriebssystem der ZielArchitektur Linux ist, haben die Programme den Prefix „armlinux“. Der Linker bekommt dann den Namen „arm linuxld“. Oftmals behalten die Programme auch ihren Namen, und es wird eine Verknüpfung mit dem Prefix „armlinix“ auf die Programme angelegt. Falls das verwendete Betriebssystem QNX ist, würde der Prefix „armqnx“ 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 ObjectDateinen 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 armlinuxreadelf Das Programm readelf zeigt Informationen über BinärDateien an, die im ELFFormat 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 ELFDatei, 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 armlinuxaddr2line 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 DebugInformationen enthalten sind, funktioniert. 8.1.3 armlinuxar Dieses Tool verwaltet ArchivDateien, welche typischerweise die Endung „.a“ tragen. Eine ArchivDatei besteht aus beliebigen Dateien, die zu einer ArchivDatei 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 BibliothekDateien 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 armlinuxranlib Ranlib macht das gleiche wie ar s und wird daher nicht näher beleuchtet. 8.1.5 armlinuxnm Das Programm nm listet Symbole, die in den übergebenen ObjectDateien 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 armlinuxsize Dieses kleine Werkzeug gibt die Größe der verschiedenen Sektionen (.text, .data, .bss) einer oder mehrerer ObjectDateien aus. Das .textSegment wird auch CodeSegment genannt, es beinhaltet den Programmcode und man kann nur lesend darauf zugreifen. Das .data und .bssSegment enthält globale und statische Variablen. Auf diese beiden Segmente kann sowohl lesend als auch schreibend zugegriffen werden. 8.1.7 armlinuxcpp Das Programm cpp ist der CPreprozessor. Er ist für die Ersetzung von Macros zuständig. Das Programm eignet sich für C, C++ und ObjectiveC Quellcode. Es wird vom Compiler, vor dem eigentlichen CompilierVorgang, aufgerufen und man kommt mit diesem Programm eigentlich nicht in Berührung. (nicht mit armlinuxgcc verwechseln) 8.1.8 armlinuxstrings 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 armlinuxgdb Dies ist der Debugger, er arbeitet als KonsolenApplikation. Mit ihm ist es möglich das Binary Schritt für Schritt zu durchlaufen, VariablenInhalte anzuzeigen und vieles mehr. Aus Bequemlichkeit wird er meist in Kombination mit grafischen Frontends verwendet. 8.1.10 armlinuxobjcopy Wie der Name der Applikation schon verrät, ist es dazu da, um ObjectFiles zu kopieren. Beim Kopieren des Inhalts der ObjectDatei kann das verwendete Format über die Parameter bestimmt werden. 8.1.11 armlinuxgcov 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 ifAnweisung, 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 GleichheitsAbfrage. 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 ifAnweisungen 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 armlinuxas Der GNUAssembler ist ein Assembler, für verschiedene Prozessoren oder besser gesagt, der GNUas stellt eine AssemblerFamilie dar. Beim armlinuxas, handelt es sich um den GNU Assembler, der für die Benutzung für armProzessoren konfiguriert wurde. 8.1.13 armlinuxobjdump Das Programm objdump zeigt verschiedenste Informationen über ObjectFiles an. 8.1.14 armlinuxstrip Strip wird dazu genutzt um Symbole aus ObjectDateien oder Archiven also statischen Bibliotheken zu entfernen. Auf Embedded Geräten ist strip sehr sinnvoll, da die Dateien wesentlich kleiner werden. Mit der Option –stripdebug, enfernt man alle DebugSymbole. Das Debuggen wird hierdurch nahezu unmöglich aber die Datei wird um einiges kleiner. 8.1.15 armlinuxld Der Linker wird am Ende eines Kompiliervorgangs aufgerufen, er linkt die ObjectDateien und Archive zu AusführbarenDateien zusammen und löst somit die Symbole auf. Im Falle des RemoteHMIProjektes, das man für X86 und armProzesooren übersetzten 115 kann, ist es wichtig, dass man bevor man für eine andere Plattform den Übersetztungsprozess abstößt, die bereits erstellten ObjectFiles 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 ObjectFiles 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 armlinuxc++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++filt2006] 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 ProzessorArchitektur 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 InCarMultimediaFramwork, 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 RemoteHMIs und die Resourcenvergabe beliebig vieler Geräte. Die konkrete Implementierung der RemoteHMI 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 XScaleProzessor 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 GUIProgrammierung mit Qt war für mich Neuland. Im Laufe des Projektes erwies sich Qt als einfaches und schnell zu erlernendes GUIToolkit 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 RemoteHMI 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 RemoteHMI 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 InCarMultimediaSystem 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 HPiPAQ 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 RemoteHMI 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 HighLevel als auch LowLevel Grafik programmiert werden. Für die Kommunikation ist es jedoch nötig, dass man geeignete BluetoothTreiber für QNX besitzt oder portiert. Des Weiteren ist es nötig, einen geeigneten ProtokollStack 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 PhytonInterpreter 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 HDRecoder an Stelle eines Verstärkers einzusetzen. Genauso gut ist es möglich, dass eine NavigationsKomponente sich anstelle einer HMI beim AudioMaster anmeldet und den TMCTuner 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 RemoteHMI bereits der Fall ist. 11.4 SoftwarePaket Wie im Abschnitt zur Software Auslieferung bereits erwähnt, sollte das RemoteProjekt als Paket verpackt werden, das dann mit dem PaketManager 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 InCarMultimediaProject 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 SocketVerbindung ü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 InCarMultimediaSysteme..................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 FloatingPointUnit............................110 M Framework...........................................17 MainDispatcher...................................18 FunctionBlockID.................................20 mangling............................................116 FunctionID..........................................21 MetaObjectCompiler........................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 OSAbstractionLayer.........................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 UserInterfaceCompiler.....................65 Qt Palmtop Environment.....................59 W QtEmbedded......................................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 SiemensS65......................................102 .ui..................................................65, 89 124 Literaturverzeichnis [WiTr2005] Wietzke, Joachim; Tran, Manh Tien Automotive Embedded Systeme : Berlin Heidelberg : Springer, 2005 [Kurz2005] Kurz, Bettina Transp. Segm. v. Nachr. z. Einb. e. AppleIPOD i. e. MOSTFramew., 2005 http://www.fbi.hda.de/fileadmin/personal/j.wietzke/ ... ... mein_ordner/Studentenarbeiten/IPOD_im_MOST_Framework.pdf Zuletzt besucht am: 07.09.2006 um 15:58 Uhr [Drex2006] Drexler, Michael SiemensS65 http://www.SiemensS65.de/ Zuletzt besucht am: 25.09.2006 um 13:55 Uhr [hp2006] HewlettPackard 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 [qnx2006] 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 [lugod2006] Linux Users' Group of Davis Grafik http://www.lugod.org/presentations/zaurustalk/pics/qtopia_02.png Zuletzt besucht am: 24.08.2006 um 10:25 Uhr [Hand2006] Handhelds.org Open Source Operating Systems for Handheld Devices www.handhelds.org Zuletzt besucht am: 28.09.2006 um 18:48 Uhr 125 [Troll2006] Trolltech Online Reference Documentation http://doc.trolltech.com/ Zuletzt besucht am: 07.09.2006 um 17:45 Uhr [Blan2004] Blanchette, Jasmin; Summerfield, Mark C++ : GUIProgrammierung mit Qt3 München : AddisonWesley, 2004 [Schm2004] Schmatz, KlausDieter Java 2 Micro Edition : Entw. mobiler Anwendungen mit CLDC und MIDP Heidelberg : dpunkt.verlag GmbH, 2004 [Sun2006] 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++filt2006] Free Software Foundation, Inc. Manual Page c++filt, 2006 Packet: binutils2.16.91 126