Vorwort | 6 |
Inhaltsverzeichnis | 8 |
Die Listings | 16 |
Abbildungsverzeichnis | 22 |
1 Einleitung | 25 |
Teil I Bausteine eines Embedded Frameworks | 29 |
2 Ein Infotainment-System | 31 |
2.1 Die Headunit | 32 |
2.1 Die Headunit | 32 |
2.2 Geräte/Devices im System | 33 |
2.3 Begriffsklärung: Was ist ein Framework | 34 |
2.4 Fokus unserer Framework-Betrachtungen | 35 |
3 Anforderungen an ein Embedded Automotive Framework | 37 |
3.1 Verteilte Entwicklung | 37 |
3.2 MVC, Organisationen | 37 |
3.3 Speicheranforderungen | 39 |
3.4 Startzeiten | 39 |
3.5 Menüwechselzeiten | 40 |
3.6 Konfiguration versus Dynamik | 40 |
3.7 Datenfluss/Kontrollfluss/Zustandssteuerung | 40 |
4 Betriebssysteme | 41 |
4.1 Prozesse, Tasks, Threads | 42 |
4.2 Der Scheduler | 43 |
4.2.1 Präemptive Prioritätssteuerung | 43 |
4.2.2 Round-Robin | 43 |
4.2.3 Prioritäts-Inversion, Prioritäts-Vererbung | 43 |
4.2.4 Task-Switch, Kontextwechsel | 44 |
4.3 Zusammenspiel mit der MMU | 44 |
5 Design-Rules und Konventionen | 45 |
5.1 Namenskonventionen | 46 |
5.2 Shared-Verzeichnisse, Libraries | 46 |
5.3 Eigene Definitionen im Shared | 46 |
5.3.1 Standard-Typen | 46 |
5.3.2 Alignment | 47 |
5.3.3 Little-Endian, Big-Endian | 48 |
5.3.4 Zahlengrenzen | 49 |
5.3.5 Const Definitionen | 49 |
5.3.6 Eigene Assertions | 50 |
5.3.7 Exceptions und Signale | 51 |
5.3.8 Eigene Ausgaben | 51 |
6 Speicherverwaltung | 53 |
6.1 Statische Speicherverwaltung | 55 |
6.2 Dynamische Speicherverwaltung | 55 |
6.3 Start-Up-Strategien | 57 |
6.4 Speicherbedarf und kleine Pittfalls | 57 |
6.4.1 Welche Variable wo? | 57 |
6.4.2 Alternative Strategie 1: Späte Konstruktion | 60 |
6.4.3 Alternative Strategie 2: Späte Initialisierung | 62 |
6.4.4 Alternative Strategie 3: Lokale statische Variablen | 63 |
6.4.5 Speicherort von Konstanten | 64 |
6.4.6 Speicherbedarf eines einfachen Objekts | 67 |
6.4.7 Speicherbedarf eines einfachen Objekts mit virtueller Methode | 68 |
6.4.8 Speicherbedarf eines Objekts einer abgeleiteten einfachen Klasse | 70 |
6.4.9 Speicherbedarf eines Objekts einer abgeleiteten Klasse mit virtueller Methode | 72 |
6.4.10 Speicherbedarf eines Objekts einer abgeleiteten Klasse mit virtueller Basis-Methode | 74 |
6.4.11 Mehrfachvererbung und Pittfall | 76 |
6.4.12 Speicherbedarf dynamischer Variablen | 79 |
6.4.13 Schlechte Parameterübergabe | 80 |
6.4.14 Probleme mit dem Kopierkonstruktor | 81 |
6.4.15 Probleme mit dem Zuweisungsoperator | 81 |
6.4.16 Schlechte Rückgaben | 81 |
6.4.17 Padding-Probleme | 83 |
6.4.18 Alignment-Probleme, Endian-Probleme | 84 |
6.4.19 Speicherfragmentierung | 84 |
6.4.20 Vektoren, STL | 85 |
7 Embedded Speicherkonzepte, spezielle Muster | 87 |
7.1 Statische Variablen | 87 |
7.1.1 Reihenfolge der Konstruktoren | 87 |
7.2 Quasi-statische Allokation aus festem Pufferspeicher | 90 |
7.2.1 Anlegen eines statischen Puffers | 91 |
7.2.2 Placement-new | 91 |
7.2.3 Makros zur Allokation | 92 |
7.3 Allokator | 94 |
7.3.1 Statische Allokation | 97 |
7.3.2 Dynamische Allokation mit temporärem Heap | 99 |
7.3.3 Object-Pool-Allokation | 102 |
7.4 Datencontainer | 106 |
7.5 Gemeinsam benutzte Objekte (Shared-Objects) | 106 |
7.6 Referenzzähler (reference counting) | 107 |
7.7 Garbage-Collection | 109 |
7.8 Die Captain-Oates Strategie | 109 |
7.9 Speicherlimit | 110 |
7.10 Partieller Fehler (Partial Failure) | 111 |
7.11 Fazit | 111 |
8 Prozesse und POSIX-Threads | 113 |
8.1 Prozesse | 114 |
8.1.1 Der Lebenszyklus eines Prozesses | 114 |
8.1.2 Prozesszustände | 115 |
8.1.3 Zombies | 116 |
8.1.4 Bestandteile | 116 |
8.1.5 Prozess mit fork erzeugen | 117 |
8.1.6 Prozess mit exec erzeugen | 118 |
8.1.7 Prozess mit spawn erzeugen | 120 |
8.1.8 Prozessvererbung | 121 |
8.1.9 Prozessattribute | 121 |
8.1.10 Über Prozessgrenzen hinweg | 122 |
8.2 Threads | 123 |
8.2.1 Erzeugung von POSIX-Threads | 123 |
8.2.2 Allgemeine Gestaltung eines Threads in eingebetteten Anwendungen | 124 |
8.2.3 Thread-Attribute | 125 |
8.2.4 Über Threadgrenzen hinweg | 128 |
8.2.5 Thread-spezifische Daten | 130 |
8.2.6 Thread-Träger und Thread-Objekte | 132 |
8.3 Designentscheidung | 142 |
9 Inter-Prozess-Kommunikationskanäle, IPC | 145 |
9.1 Pipe | 145 |
9.2 FIFO, Named-Pipe | 149 |
9.3 Socket, local | 149 |
9.4 Socket-Verbindung zwischen Prozessoren | 151 |
9.5 Message-Queues | 158 |
9.5.1 System V Message-Queues | 158 |
9.5.2 POSIX Message-Queues | 158 |
9.6 QNX-Message | 161 |
9.7 Shared-Memory | 161 |
9.8 Shared-Memory gegen Überschreiben sch utzen | 168 |
9.9 Zeitverhalten | 173 |
9.10 Designentscheidung und prinzipielle Implementierung | 174 |
10 Gemeinsame Nutzung von Code | 175 |
10.1 DLLs | 175 |
10.2 Shared-Code | 175 |
10.3 Designentscheidung und prinzipielle Implementierung | 176 |
11 Synchronisierungsmechanismen für Prozesse und Threads | 177 |
11.1 Semaphore | 177 |
11.2 Unbenannter Semaphor | 181 |
11.3 Benannter Semaphor | 184 |
11.4 Mutex, rekursiver Mutex | 185 |
11.5 Mutex-Guard | 191 |
11.6 Signale | 192 |
11.7 Bedingungsvariablen (Condition Variables) | 192 |
11.8 Zeitverhalten | 201 |
11.9 Deadlock, Livelock und Prioritätsinversion | 201 |
11.10 Zusammenfassung | 206 |
12 Kommunikation per Events | 207 |
12.1 Wichtige Event-Typen | 208 |
12.1.1 Signal-Events | 208 |
12.1.2 Events mit Cookies | 209 |
12.1.3 Call-Events | 209 |
12.1.4 Timer-Events | 209 |
12.1.5 Change-Events (Notifikation - Das Hollywood-Prinzip) | 210 |
12.2 Realisierungen von Events | 210 |
12.2.1 Einfache Events | 210 |
12.2.2 C-Strukturen | 211 |
12.2.3 Funktionszeiger | 213 |
12.2.4 Event-Klassen und Objekte | 214 |
12.2.5 Zeiger auf Event-Objekte verschicken | 216 |
12.2.6 Events am Beispiel von MOST | 219 |
12.3 Designentscheidung und prinzipielle Implementierung | 220 |
13 Event-Verarbeitung | 221 |
13.1 Queues | 221 |
13.1.1 Externe Queue | 223 |
13.1.2 Interne Queue | 228 |
13.1.3 System-Queue | 229 |
13.1.4 Queue mit verbesserter Inversions-Eigenschaft | 229 |
13.2 Dispatcher | 235 |
13.2.1 Der System-Dispatcher | 235 |
13.2.2 Der lokale Dispatcher | 236 |
13.2.3 Signalisation im Dispatcher | 237 |
13.2.4 Registrierung im Dispatcher | 237 |
13.3 Synchrone Events | 238 |
14 Zustandsautomaten | 239 |
14.1 Motivation | 239 |
14.2 Kommunikation | 240 |
14.3 Automaten | 241 |
14.4 Statechart-Elemente | 241 |
14.5 Probleme mit Statecharts und Ersatzl osungen | 245 |
14.6 Implementierung dynamischen Verhaltens | 247 |
14.6.1 Definition der Events | 248 |
14.6.2 Implementierung der Aktionen | 249 |
14.7 Implementierung der Statecharts | 250 |
14.7.1 Implementierung durch Aufzählung für Zustände und Unterzustände | 250 |
14.7.2 Zustandsmuster (State-Pattern) | 255 |
14.7.3 Verbesserte Aufzählungsmethode | 264 |
14.8 Implementierung nach Samek | 270 |
15 Externer Kommunikationskanal: MOST-Bus | 277 |
15.1 Der synchrone Kanal | 278 |
15.2 Der asynchrone Kanal | 279 |
15.3 Der Kontrollkanal | 279 |
15.4 Geräte/Devices im Framework | 279 |
15.4.1 Logische Geräte, Modelle | 281 |
15.4.2 Methoden | 282 |
15.4.3 Properties | 282 |
15.4.4 MOST-Adressierung | 283 |
15.4.5 Adressierungsbeispiele | 289 |
15.4.6 MOST-Events, prinzipielle Dekodierung des Headers | 290 |
15.4.7 MOST-Events, prinzipielle Dekodierung der Daten | 292 |
15.4.8 MOST-Konstanten | 293 |
15.4.9 MOST-Probleme | 295 |
Teil II Das Framework | 298 |
16 Das Framework | 299 |
17 OS-Grundmechanismen | 301 |
18 Komponentenarchitektur | 303 |
18.1 Event-Handler und Event-Formate | 305 |
18.2 Implementierung von Schnittstellen, Proxy und Handler | 309 |
18.3 Komponentenarchitektur | 311 |
18.3.1 Komponentenkontext und Daten im Shared-Memory | 312 |
18.3.2 Erzeugung der Kontexte | 319 |
18.3.3 Main-/Admin-Task | 324 |
18.3.4 Signale, Mechanismen über den Kontext | 326 |
18.3.5 Komponenten-Dispatcher | 332 |
18.3.6 Softtimer und Timer-Manager | 334 |
18.3.7 Registrierung | 342 |
18.3.8 Die Basisklasse AComponentBase und das Zusammenspiel mit der Umgebung | 343 |
18.4 Zusammenfassung | 351 |
19 Main-Dispatcher-Komponente | 355 |
19.1 Dispatcher-Receiver | 355 |
19.2 Dispatcher-Main-Thread | 360 |
20 Modell-Komponenten, logische Geräte | 365 |
20.1 Aufgaben des logischen Geräts | 366 |
20.2 Was erwartet die HMI von einem logischen Gerät? | 367 |
20.3 Zustände des Geräts | 369 |
20.4 Gültigkeit der Daten | 370 |
20.5 Kommunikationsanforderung | 371 |
20.6 Struktur eines logischen Geräts | 371 |
20.7 Datencontainer versus Event-Prinzip | 371 |
20.8 Architektur eines Datencontainers | 373 |
20.8.1 Struktur des Datencontainers | 374 |
20.8.2 Lesezugriffe der HMI | 380 |
20.8.3 Versenden eines HMI-Befehls | 381 |
20.8.4 Menge der erlaubten High-Level-Aktionen | 382 |
20.8.5 Abstrakte Klasse ADataContainerAccessor | 383 |
20.9 MOST-Codec | 387 |
20.9.1 Vorbereitung | 387 |
20.9.2 Einfache Implementierung eines MOST-Decoders | 391 |
20.9.3 Objektorientierter Ansatz | 394 |
20.9.4 Objekte zur Kompilierzeit | 396 |
20.9.5 Konstante Objekte zur Dekodierung der MOST-Nachrichten | 398 |
20.10 Zusammenfassung | 411 |
21 HMI-Komponente | 413 |
22 Persistenz-Controller und On/Off-Konzepte | 415 |
23 Codegenerierung | 419 |
23.1 Erstellen der XML-Eingabe-Dateien | 419 |
23.2 Erzeugen des Quellcodes | 421 |
23.3 Übersicht der erzeugten Dateien | 422 |
23.4 Übersetzen des Quellcodes | 428 |
24 Sonstige Aspekte | 429 |
24.1 Internes non-MOST-Device, Beispiel Mediaplayer | 429 |
24.2 Internes MOST-Device, Beispiel Tastatur | 429 |
24.3 Treiber im Framework | 430 |
24.4 Einfaches Debugging-Konzept | 430 |
24.5 Überlastverhalten des Systems | 432 |
24.6 Anmerkungen zur Komplexität und zum Testing | 433 |
25 Anhang | 435 |
25.1 Timer und Zeitmessung | 436 |
25.1.2 Timeout | 438 |
25.2 Socket | 438 |
25.2.1 InetAddr | 438 |
25.2.2 CSockAcceptor | 439 |
25.2.3 CSockConnector | 442 |
25.2.4 CSockStream | 444 |
25.3 Keyboard | 446 |
25.4 Shared-Memory | 448 |
25.5 CBinarySemaphore | 456 |
25.6 Extern const | 463 |
Literatur | 465 |
Index | 467 |