CRuntimeJavalike - Modules/Dependencies

CRuntimeJavalike - Modules/Dependencies

Inhalt


1 Grundsätzliches zu Abhängigkeiten, Modul- und Layerstrukturen

Topic:Programming.ModulStructure.Dependencies

Die Beachtung von Abhängigkeiten in der Software sind ein wichtiges Thema der Softwarepfege, oft unterschätzt. Intuitiv erstellte Software ohne Abhängigkeitsprüfung und Diskussion läuft zunächst nach einer gewissen Inbetriebnahmephase, doch bei Änderungen an der einen Stelle gibt es oft unerwartete Nebeneffekte... Software, bei der Abhängigkeiten richtig designed sind, kann man an einer Stelle korrigieren, und hat entweder keine Nebenwirkungen, oder Korrekturen an allen ähnlichen betreffenden Stellen gratis mit, bevor dort Fehler überhaupt auffalllen.


siehe auch DependenciesInSoftware


2 4 Layer als Basis beliebiger Anwendersoftware

2.1 Layer im Hardware/OS-Bereich und Anwendung

Topic:LibJc.Layer.OsLayerAndAppl

Typisch für Embedded-Applikationen ist, dass diese eng mit einer bestimmten Hardware zusammenarbeiten müssen. Die Hardware besteht aus möglicherweise Spezialprozessoren, oft einem oder mehreren FPGA (Field Programmable Gate Array, programmierbare Logik) und spezifischen Signalverarbeitungen, an die möglicherweise Leistungshalbleiter, Schütze und Relais, spezielle Messwerterfassungen angekoppelt sind. Die Verarbeitung im Prozessor erfolgt im Takt der Einganssignale (Echtzeit) und ist oft an ein spezielles mehr oder weniger allgemein gebräuchliches Betriebssystem gekoppelt.

Die Software ist mehr und mehr umfangreich, da das Leistungsvermögen der Prozessoren steigt und die Eigenschaften der Geräte diesem Leistungsvermögen entsprechenden Wünsche erfüllen sollen. Wo früher eine spezielle Assemblerprogrammierung ausgereicht hat, um den geforderten Funktionsumfang zu realisieren, kann heute eine komplex Software implementiert werden.


Bild: Layer und Applikationssoftware

Das Bild zeigt die Verbindung der Layer ab der Hardware bis zu CRuntimeJavalike mit der Applikation.

Die Applikation ist teilbar in zwei Bereiche:

Früher hat man sich vorderhand auf den orangenen Teil konzentriert. Die Software was sowieso hardwaregebunden, wurde in Assembler speziell auf die Hardware zugeschnitten. Heute sind die Anforderungen an die Funktionalität gestiegen und die Entwicklungszeiten und -kapazitäten der Software sind dennoch nicht größer geworden. Diese Schere kann man nur überwinden, indem der Softwareentwicklungs- und -testprozess effektiviert wird und Software wiederverwendet wird. Damit kann sich diese Software aber nicht auf die bestimmte Hardware konzentrieren sondern muss allgemeiner realisiert werden.

Der Teil der Software, der an die Hardware gebunden sein muss, wird neben speziellen Bedingungen der Hardwareankopplung auch die spezifischen Leistungseigenschaften des vorhandenen Betriebssystems (OS) nutzen wollen und müssen. Dieser Teil der Software muss spezifisch programmiert werden.

Der größere Teil der Software, der übergeordnete Teil, soll aber keine Hardwarespezifika beachten müssen (diese werden durch den orangenen Teil gekapselt) und braucht oft auch nicht die spezifischen Eigenschaften des Betriebssystems ausnutzen. Dieser Teil der Software ist mit den nachfolgenden Darstellungen über ein OSAL- und Jc-Layer angesprochen. Dafür gilt:

Das ein solcher Test auf PC-/Modul-Ebene ein Integrationstest des Gerätes nicht ersetzt, dürfte klar sein. Beide Test-Strategien sind notwendig.

Die Erstellungszeit der Software vermindert sich oft beträchtlich, wenn die Software am PC mit einer gängigen IDE erstellt und vorgetestet wird. Faktoren liegen im Bereich 2 bis 5.


2.2 Allgemeingültige Definitionen - os_types_def.h als unterstes Layer

Topic:LibJc.Layer.os_types_def

Das unterste hier beschriebene Layer ist das Headerfile <os_types_def.h>. Dort sind Basistypen so definiert und in ihrer Implementierung so festgelegt, dass der Compiler sie im Zusammenspiel mit dem Zielprozessor in der notwendigen Art realisiert. Dazu gehören


Bild: Layer os_types_def.h

Dieses Headerfile soll überall als Erstes eingezogen werden. Das ist meist schon wegen der Basistypen notwendig, die in C/C++ nicht in der notwendigen Weise standardisiert sind.

Implementierungen des Betriebssystems, die oft von Fremdherstellern stammen, oder Software aus anderen Bereichen verwenden meist eine ähnliche Strategien und Headerfiles für diesen Aspekt. So heißen beispielsweise die Grundtypen auch i32 oder dergleichen, oder FS_I32 mit einem Präfix wegen der Eindeutigkeit. Diese Tatsache ist im Bild mit einem weiteren rotem Kästchen unterhalb OS angedeutet. Es ist so, dass eine Abstimmung der Verwendung von Bezeichnungen zu einem Fremdhersteller kaum erfolgen kann, hier hat ein C-Standardisierungsgremium leider geschlafen. Eine Abstimmung von vorhandener Software kann wegen des Änderungsaufwandes nicht erfolgen, und eine Abstimmung mit anderen Softwareentwicklungsabteilungen gestaltet sich oft schwierig, weil jeder sich seine eigene Welt bereits eingerichtet hat. Allerdings ist das kein Problem, da zueinander passende Typdefinitionen vom Compiler erkannt werden. So ist eine Zuweisung eines FS_I32-returnwertes zu einem int32 überhaupt kein Problem. Diese Welten können parallel bestehen bleiben. Man sollte in der eigenen Software die eigenen Typbezeichnungen wählen.


2.3 Basis-Routinen in C (BaseC)

Topic:LibJc.Layer.base

Es gibt eine Reihe von Basisfunktionalitäten,

Solche Funktionalitäten können in einer Basis-Library zusammengefasst werden. Diese Basislibrary kann für embedded-Anwendungen eine libc auch ersetzen. Diese Basis-Library soll auf der untersten Ebene zur Verfügung stehen und demzufolge in den OSAL-Betriebssystemanpassungen verwendet werden können.


2.4 OSAL - Layer (OSAL.a)

Topic:LibJc.Layer.osAdaption

Software sollte aus Anwendersicht unabhängig vom Betriebssystem sein. Nur dann ist es einerseits möglich, Algorithmen und Funktionalitäten in einer anderen Umgebung, gegebenenfalls mit simulierten Außenschnittstellen, zu testen. Andererseits wird so ein Einsatz auf verschiedenen Hardwareplattformen möglich. Das trifft insbesondere für embedded-Software zu.

Um diese Unabhängigkeit vom Betriebssystem zu erreichen, ist folgend eine OSAL-Schicht definiert (OSAL = Operation System Adaption Layer). Die Implementierung ist dabei os-spezifisch. Die Definition der Schnittstellen einschließlich des Programmtextes der Headerfiles ist aber os-unspezifisch. Die meisten Betriebssysteme bieten vergleichbare Funktionen, nur alle ein wenig anders. Die OSAL-Implementierung ist zumeist eine relativ dünne Schale um die vom Betriebssystem bereitgestellten Funktionen. In wenigen Fällen, für unpassende Betriebssysteme, muss mehr getan werden.


2.5 Allgemeines Basis-System/Framework in C (Fwc.a)

Topic:LibJc.Layer.framework

C und C++ definiert zuwenig Dinge als einheitlichen Standard. Das ist ein Zugeständnis an Maschninen-Nähe - dies braucht Flexibilität. So ist beispielsweise die Datenbreite von int-Variable für jeden Compiler anders wählbar und zweckmäßigerweise an die Registerbreite des Prozessors gebunden. long ist größer oder gleich int, es ist aber nirgends festgeschrieben, dass long immer 32 bit breit sein muss. Ähnlich ist es mit short. Was in C und auch in C++ fehlt, ist die Definition von Basistypen mit einer plattformunabhängig festgelegten Bitbreite, die für eine portable Programmierung wichtig wäre. Die Folge ist, dass in jedem Projekt und/oder für jede Plattform anders bestimmte Festlegungen getroffen werden, wie Datentypen für feste Bitbreiten definiert werden. Beispiele sind i16, int16, Int16, I2 für den Integer-Datentyp, der 16 bit umfasst. Ziel von Basis-Headerfiles eines Framework ist es, solche Definitionen einheitlich festzulegen und allen Anwenderprogrammen zugänglich zu machen. Dabei sind vorhandene oder zugelieferte Software, die gegebenenfalls andere Regeln hat, mit zu integrieren. So ist es kein Widerspruch, verschiedene Bezeichnungen zuzulassen und per #define gleichzusetzen, wohl aber auf die Verwendung einer bestimmten Bezeichnung für Neuentwicklungen hinzuweisen.

Die Definition von Basis-Funktionalitäten umfasst mehr noch als diese Grundtypen. Genaugenommen wird damit eine C/C++-Spracherweiterung definiert, die projektübergreifend gelten sollte. Je allgemeingültiger und anwendungsbreiter diese ist, desto weniger Detail- und Nachaufwand hat man bei der Pflege und Integration von Software. Ähnliche Spracherweiterungen bringen die meisten zugekauften Programmierumgebungen oder Standard-Library-Angebote ebenfalls mit. Das Problem hierbei ist, dass es keine Einheitlichkeit gibt und dass das Anpassungen einen gegebenenfalls schwer handhabbaren Eingriff in ein Kaufteil darstellen. Man hat Schwierigkeiten, wenn man plattformübergreifend programmieren will, sich aber an eine bestimmte zugekaufte Plattform orientiert. Daher ist es oft zweckmäßiger, sich nicht eine bestimmte Plattform unterzuordnen sondern stattdessen das allgemeingültige Framework selbst zu definieren und an die einzusetzenden Plattformen anzupassen. Der Aufwand dazu ist oft niedriger als die sonst notwendigen Anpassungsprobleme.


Topic:LibJc.Layer.framework.platformConv

Bestimmte Verhaltensweisen sind für eine Plattform anders zu definieren als für eine andere, obwohl die Aufrufbedingungen gleich sind. Typisches Beispiel ist die Reaktion auf Fehler. Während in einer Testumgebung bei Fehlern einfach angehalten werden soll, um den Gesamtzustand untersuchen zu können (Debugger-Nutzung), kann auf einer Zielplattform beispielsweise ein Logeintrag erzeugt werden, gegebenenfalls in einem internen Speicher, aber das Gerät soll möglichst weiterarbeiten.

Diese Festlegungen gelten unabhängig von der Applikation für das Gerät oder die Art der Anwendung oder für die Platform. Daher werden sie auf dem Layer des Frameworks plattformabhängig implementiert und stehen dabei allen Layern oberhalb zur Verfügung.


Topic:LibJc.Layer.framework.platformConvFromOSAL

Um auch Betriebssystem-Meldungen über diese Funktionalität führen zu können, ist im OSAL-Layer ein callback-Mechanismus eingebaut, der dynamisch auf dieses Layer verweist. Damit kann die OSAL-Implementierung zwar unabhängig von der Art der Anwendung (der gewünschten Fehlerreaktion) sein, dennoch ist an dieser Stelle bestimmbar, wie eine Fehlerbehandlung erfolgt. Man muss also nicht das OSAL-Layer einer Art der Anwendung anpassen.


2.6 CRuntimeJavalike (Jc.a)

Topic:LibJc.Layer.Jc

Das hier genannte Jc-Layer ist das eigentliche CRuntimeJavalike-Layer. Es enthält diejenigen Funktionalitäten, die zur Abbildung der Java-Basisklassen notwendig sind und in C anders zu implementieren sind als in Java. Teils ist der Java-Code auch im C nachempfunden worden.

Die Problematik des Fehlens eines wirklichen Standards in C und C++ für Basisfunktionen führt zu der Frage, ob eine Anlehnung an eine der vorhandenen Quasi-Standards erfolgen soll. Eine Anlehnung an ein vorhandens System und eine entsprechende Umsetzung für die konkreten Belange ist immer eine bessere Wahl als Algorithmen und Schnittstellen frei selbst erfinden, da die Erfahrungen des vorhandenen Systems einfließen.

Die Programmiersprache Java enthält in ihrem Standardausbau alle notwendigen Basisfunktionalitäten für

Die Entwicklung von Java konte hierbei profitieren von allen Erfahrungen der Programmierung, die bis zum Erscheinen von Java etwa 1995 vorhanden waren. Einhergehend damit ist auch die Reduktion auf einfache Mechanismen dort, wo eine Vorentwicklung zunächst übermäßig komplexes hervorgebracht hat und aus Kompatibilitätsgründen weiter beibehalten muss. Neuere Entwicklungen wie beispielsweise die Lock-Free-Programmierung oder Umgang mit Zeichencodierungen sind in Java als Erweiterungen eingeflossen. Damit bietet Java ein Basissystem, welches fein abgestimmt insbesondere für embedded control geeignet ist. Die ursprüngliche Fokusierung von Java lag auf Internet-Anwendungen, die auf jedem System eingebettet laufen sollten. Aufgrund des Potenzials von Java wurde dieses aber dann neben Standard-PC-Anwendungen in embedded Systemen angewendet und ist dort bewährt. Damit ist eine Anlehnung an Funktionalitäten, wie sie in Java vorhanden sind, für ein allgemeines Basissystem geeignet.

Java arbeitet immer mit Unterstützung einer sogenannten Virtuellen Maschine (VM) und ist somit abkoppelbar von Eigenheiten des umgebenden Systems. Die VM basiert allerdings auch auf einfachen Abarbeitungsregeln, die meisten Sprachkonstrukte und Funktionalitäten in Java passen auf eine maschinenorientierte Abarbeitung in C. Die VM-Orientierung stellt also kein Hindernis der Nutzung von Java-Prinzipien dar.

Sämtliche Algorithmen des Submoduls Jc sind in C programmiert und getestet und benötigen weder eine VM noch etwas anderes aus Java. Die Java-Orientierung besteht lediglich in der Ähnlichkeit der Wahl der Funktionalitäten einschießlich der Bezeichnungen. So gibt es beispielsweise eine Klasse LinkedListJc, die funktionell der Klasse java.util.LinkedList entspricht. Eine C-Routine add_LinkedListJc(...) führt funktionell vergleichbares aus wie die add(...)-Methode der Java-Klasse. Es sind nur jeweils diejenigen Funktionalitäten aus Java realisiert, für die es auch konkrete Anwendungsfälle gibt.

Alle Quellen des Layers Jc sind zuerst in C programmiert und auch mit einem C-Compiler übersetzbar. Einer Klasse in Java entspricht immer ein Komplex von C-Routinen mit einer entsprechend benannten Datenstruktur. Für die Erleichterung der Anwendung in C++ gibt es jeweils einen C++-Klasse als Wrapper. Insbesondere bei String-Verkettungen können hierbei Schreib-Erleichterungen genutzt werden, da C++ die Definition von Operatoren gestattet. Ein Zugriff aus einem UML-Modell wie beispielsweise mit (Rhapsody ist ebenfalls möglich mit Bereitstellung der entsprechenden Modell-Elemente und Verbindung mit der hier vorhandenen externen Implementierung..


2.7 Nutzung der Schichten in der Anwendersoftware

Topic:LibJc.Layer.WhatToUse

Diejenige Software, die speziell für die Zielplattform geschrieben ist und nur mit der Zielplattform gemeinsam sinnvoll testbar ist, darf alle Schnittstellen, die auf der Zielplattform vorhanden sind, nutzen. Das sind direkte Zugriffe auf die Hardware, spezielle Eigenschaften des Betriebssystems, aber auch die hier vorgestellten Layer unterhalb der Applikation. Bei dieser Software handelt es sich um die Treiber- und Interruptebene. Diese Softwareteile sind meist algorithmisch nicht komplex. Die Applikationssoftware ruft diese Teile auf bzw. wird dort aufgerufen.

Reine Applikationssoftware, die auf einem PC modulgetestet werden soll, darf direkt weder Hardwarezugriffe ausführen noch die Schnittstellen des Betriebssystems direkt nutzen. Es sind nur Zugriffe über die OSAL-Schicht zulässig. Diese Applikationssoftware kann aber die plattformorientierten Routinen aufrufen, die in der Testumgebung am PC entsprechend zu emulieren sind.

Es kann empfohlen werden, aus der Sicht der Applikationssoftware auch nicht die OSAL-Routinen aufzurufen. Die OSAL-Schicht ist damit 'nur' die Anpassungsschicht zum Betriebssystem aus den darüber liegenden Systemlayern Fwc, Jc und den plattformorientierten Routinen. Das ist damit zu begründen, dass die darüberliegenden Schichten Fwc und Jc noch einige Checks ausführen können. Außerdem sind dann bei Änderung der OSAL-Schnittstelle keine Anwender-Routinen betroffen. Fwc und Jc kapseln die OSAL-Schicht also in zweckmäßiger Art nochmals.

Die Frage, ob eine Anwenderroutine sich stark an der Jc-Schicht orientiert, hängt davon ab, ob das Javalike-Konzept von allen Softwareerstellern der Anwenderschicht akzeptiert wird. Einerseits gibt es bei bereichsübergreifender Zusammenarbeit oft Abstimmungsschwierigkeiten, eine Javalike-Herangehensweise zu vereinbaren ist dabei nochmals schwieriger als sich auf bestimmte OS-Zugänge über OSAL zu einigen. Daher ist die kleinere Schnittmenge schonmal ein Erfolg. Möglicherweise kann dann der zweite Schritt nach Bewährung des Ersten gegangen werden. Andererseits ist es auch schon vorgekommen, dass Java in bestimmten Entwicklerkreisen vollständig abgelehnt wurde, sei es aus Unkenntnis oder Vorbehalten. Letzteres ermöglicht keine Sachdiskussion, so dass diese Ebene einer gemeinsamen Softwareplattform sich mindestens für ausgetauschte Software zurückziehen muss. Das ist auch der Grund der Definition eines extra Fwc-Layers, das bei genauerem Hinsehen Java-like-Konzepte enthält, die aber nicht so benannt wurden. Diese Teile müssen in gemeinsamer Software enthalten sein, wenn darauf aufbauender Teile die Javalike-Konzepte nutzen wollen.


3 Inhalte der Layer

3.1 Basis-Routinen in C (BaseC.a)

simple time conversion, string-base, Ausgabeformatierungen (sprintf-like),


3.2 OSAL - Layer (OSAL.a)

TODO (Basis-Datentypen, Threads, File-IO, Mutex, Synchronisation, Mem-Zugriff, Socket)


3.3 Allgemeines Basis-System/Framework in C (Fwc.a)

TODO (Exception, LogMessage, Object, Framework-Conventions


3.4 CRuntimeJavalike (Jc.a)

Topic:LibJc.Layer.Jc.fnOverview

Folgende Funktionalitäten sind im Jc-Modul realisiert (Überblick)

Das Submodul Jc basiert auf dem Submodul Fwc und auf der OSAL-Schicht.