A Framework for Experiments in
Real-Time Programming
plus Public Domain Java Software.

(An extract of the book titled "Sichere und fehlertolerante Steuerungen")
Sergio Montenegro (http://www.first.fhg.de/~sergio)
GMD-FIRST (http://www.first.fhg.de)
Rudowerchaussee 5
D-12489 Berlin

 

For the development of safety-relevant real time-embedded systems, whose failure can have deadly consequences, ADA is the most suitable programming language. Many developers persist nevertheless in C and C++, although these languages are classified as very unsafe. For the c-rebels there is a new hope now: Java. Java combines safety with the prefered C (and C++) syntax. But several difficulties have to be removed before Java becomes the ideal programming language for safety-relevant embedded real time systems. Actually, ADA should be the first choice but the personal inclination of the programmer plays a very important role. At the time, Java is for these applications hardly suitable, but the interest and potential in it are enormous. Java is still a very young language and its deficiencies are well-known.

Many organizations world-wide work very intensively in order to make Java the ideal programming language for such applications. The following table compares these languages.

Language

C/C++

ADA

Java

new Real time Java

Safety

- -

+ +

+ +

+ +

I/O

+ +

+ +

- -

- -

Real Time

-

+ +

- -

+ +

Efficiency

+ +

+

- -

0

Parallelism

- -

+ +

+ +

+ +

Legibility

- -

+

+

+

Flexibility

+ +

0

0

0

Portability

-

+

+ +

+ +

The criteria are sorted on their importance for the area of safety-relevant embedded real time systems. For these applications safety is most important and this is the biggest weakness of C/C++. The I/O binding and the real time support are important to embed the control software into its environment (HW + time). Exactly this and the insufficient efficiency are the weaknesses of Java.

The largest deficits in real time applications Java shows in the implementation of the Garbage Collectors and its extremely dynamic memory management. Many organizations world-wide work very intensively on these points.

The Java efficiency has two deficits: 1) The slower execution due to the interpretation. 2) The relatively large memory utilization for interpreter or for the Just in time compiler. In order to eliminate this bottleneck, special Java processors are beeing developed. For those, which cannot replace their processor, we are developing public domain compiler/translator for byte code to "C". Thus these two efficiency deficits are removed. At the URL "http://www.first.fhg.de/~sergio/public_domain.html" we have placed also a public domain frame work to experiment on real time java.

The framework technology is a further step following the object oriented technology where the functionality is provided by OO methods in the form of classes. The user can employ each class as it is, or he can tailor (adapt) the class to his own needs, by means of inheritance and methods/operators overloading.

The framework technology offers complete adaptable structures of classes. A framework is composed of several classes in a structure with different relationships: inheritance, references and contention. The whole structure has a specific complex functionality. The user can adapt its functionality to his needs.

 

Some classes in the structure provide the adaptation interface for the user. Other classes offer a function interface or support the whole framework function. To adapt the functionality of the framework to his need, the user writes new classes, which inherit from the adaptation interface classes (subclasses). The adaptation interface methods should be overloaded with the user methods and functionality in order to integrate the user functionality into the framework. The new subclasses are integrated automatically (by inheritance) into the structure. The framework functionality is thus extended by the desired functionality and adapted to the user's needs. The functionality of the entire framework is called via methods of the function interface classes.

A Real-Time Kernel as an Example of a Framework

This example represents a rather small framework, normally a framework uses more than 10 classes.

 

The class "TimeInterval" does not belong to the framework itself, it merely helps the calculation of time intervals. It implements methods for handlng time points and time intervals, allowing them to be measured, to be marked and to be compared.

The framework features an interrupt mechanism and a time-driven scheduler. These mechanisms activate the corresponding "TimedEvents" (tasks) at the right (or required) time according to a programmed response to an interrupt or to a programmed time schedule. The "TimedEvents" defined in the framework have no operation (nop) yet. The user has to write the desired function in a subclass of "TimedEvent" and overload the corresponding method "handle()" and/or "interruptHandle()". After this procedure, the framework automatically activates the methods defined by the user at the corresponding time.

The other adaptation interface class is the "OnGoing" class. With this class the user can implement an ongoing task, which runs independently of interrupts and time schedules but which can synchronize itself with time and interrupts. To achieve this synchronization the "OnGoing" class offers some methods which can be called from its subclasses. The user should write his desired functionality in a subclass of the "OnGoing" class and overload the method "run()".

Interrupt Handling

The class "InterruptTable" manages the interrupts and their servers. The interrupts are not identified by numbers but by names (String). It is possible to register (subclasses of) "TimedEvents" as interrupt servers using the method "InterruptTable.register()" and to cancel them using the method "InterruptTable.cancel()". The field "TimedEvent.interruptIds" should contain a list of interrupt names, separated by blanks " " (e.g. "hot cold low"), which the server (a subclass of "TimedEvent") should handle.

The interrupt producers signal an interrupt by calling the method "InterruptTable.raise (id)" and passing the name of the interrupt as a parameter. The InterruptTable then activates the corresponding servers by calling their interruptHandle method. The corresponding servers are all registered servers that contain the raised interrupt name in their interruptIds string.

Example of an interrupt server:

Time-Driven Scheduling

The class "RTScheduler" is a time-driven scheduler. It is possible to register (subclasses of) "TimedEvents" and their time constraints. The scheduler tries to fulfill these time constraints as well as possible (without any guarantee) and activates the corresponding task (subclass of "TimedEvent") by calling its "handle()" method at the corresponding time.

The field "TimedEvent.programmedTime" contains the time (in milliseconds) at which these tasks should be activated for the first or the next time. The field "TimedEvent.cycleTime" determines the period in milliseconds for cyclical executions. If the cycleTime field equals zero, then the task is activated only once.

The "RTScheduler" offers several methods to register "TimedEvents", for example:

  • at (time,...): for a single activation at the given time
  • every (cycle,...): for cyclical activation with the given period
  • after (time,...): for a single activation after the given time
  • schedule (...): for activation as programmed in the fields "programmedTime" and cycleTime.

 

A task can be cancelled via the "RTScheduler.cancel" method.

Example of a timed task:

OnGoing Tasks

Ongoing tasks are not activated repeatedly like the interrupt servers or the periodical tasks. They are activated only once and then run for as long as required. Instead of a "handle()" method, the "OnGoing" class has a "run()" method, which has to be overloaded in order to integrate the user functionality in the framework. The "run()" method should not use the processor all the time, otherwise other tasks cannot be executed. It should call a "yield()" or a "wait...()" function repeatedly. The "OnGoing" class offers some methods for synchronization with time and interrupts. For example:

  • waitInterrupt(timeout): waits for one of the interrupts named in interruptIds, but not longer than the indicated timeout
  • waitTime(time): waits as long as indicated
  • waitUntil(time): waits until indicated time.

 

Example of a Ongoing Task with interrupt synchronization:

 

Java Public-Domain Software to Experiment with

We have implemented a real-time framework described here tor the purpose of experimentation and for the development of real-time control and simulation environments. We are now offering this real-time kernel as Public-Domain software at the following URL

http://www.first.fhg.de/~sergio/public_domain.html

The scheduler is dynamic not preemptive. It supports periodical, sporadic and spontaneous tasks (without time windows). Ongoing tasks can run as separate Java-Threads independently of the scheduler, but they get some support for synchronization.

The use the frameworks is illustrated with a small graphic example. The structure of the example is:

 

 

 

The demo creates four equal tasks (TimedEvents) which run with different periods and react to different interrupts. The interrupts are simulated and generated in response to the user's keyboard events. The periodical Task DemoPainter paints a growing square which changes its color after each interrupt. The DemoOnGoing task measures the time between the interrupts, but after waiting for longer than 10 seconds, it becomes nervous. The DemoKeyListener generates the interrupts in response to the keyboard events. DemoDrawArea is the "main method of the framework" and creates all other objects.

A few more Informations from my www pages

Mein Buch: Sichere und Fehlertolerante Steuerungen
Sergio Montenegro, Hanser Verlag, Sept. 1999, ISBN: 3-446-21235-3

Papers about real time and control systems
http://www.first.fhg.de/~sergio/public

Seminar at the TU-Berlin
http://www.first.fhg.de/~sergio/seminar