I-RT04-HOME

  1. Einführung

  2. RTAI Kurzbeschreibung

  3. Klonen eines Projektes unter ELinOS

  4. Umschreiben eines geklonten Projektes: rtai_hello.c

  5. Das Demoprojekt cscope

  6. Testfragen und Übungaufgaben


I-RT04 REALZEITSYSTEME WS04
VL10+11: Realzeitbetriebssysteme: Anwendungen mit RTAI

    Achtung : Skript gibt den mündlichen Vortrag nur teilweise wieder !!! 
	Achtung : Skript noch nicht abgeschlossen !!!
                        

AUTHOR: Gerd Döben-Henisch
DATE OF FIRST GENERATION: September-16, 2003
DATE OF LAST CHANGE: Jan-23,2005
EMAIL: doeben_at_fb2.fh-frankfurt.de



1. Einführung

Diese Vorlesungen leiten über von den abstrakten Modellen von Realzeitsystemen zu mindestens einem konkreten Realzeit-System. Die wichtigsten 'Elemente eines abstrakten Realzeitsystems sind im nachfolgenden Schaubild nochmals festgehalten. Es sind die Ereignisse, die Tasks, die verfügbare Resourcen sowie ein Schedulingmechanismus.



RTSYSTEME

Realzeitsysteme



Als Beispiel für ein konkretes Realzeitsystem hatten wir uns für RTAI entschieden, das im Verbund mit Linux ein für viele kleinere Anwendungen günstige Lösung darstellt. In den letzten beiden Vorlesungen hatten wir kurz die Grundstruktur Linux untersucht und uns damit bekannt gemacht, welche Rolle Module unter Linux spielen. Die Motivation dafür ergab sich daraus, dass RTAI unter Linux durch Aufrufen von Modulen installiert wird (siehe nächstes Schaubild).



RTSYSTEME-LINUXRTAI

Realzeitsysteme mit Linux und RTAI



In dr heutigen Vorlesung werden wir uns mit ersten Eigenschaften von RTAI selbst vertraut machen sowie anhand eines einfachen Beispiels betrachten, wie wir eine erste kleine Anwendung unter RTAI realisieren können.


START



2. RTAI Kurzbeschreibung

Als Quelle für die folgende Darstellung von RTAI siehe einmal das Usermanual der Sysgo AG zu ELinOS v2.2 sowie die Beiträge des Entwicklerteams von RTAI ( siehe [DIAPM-RTAI [2000]: DIAPM RTAI - Beginner's Guide (Weblocation), (Lokal), Realtime Application Interface for Linux (Erklärung der Systemaufrufe) + Programming Guide).

In einer Kurzbeschreibung kann man sagen, dass es sich bei RTAI um einen kleinen Echtzeitkern handelt, der Linux in einer eigenen Task ablaufen läßt. Linux ist dabei die Idletask, die nur dann aufgerufen wird, wenn keine andere Echtzeittask lauffähig ist. Linux-Interrupts werden vom RTAI abgefangen und in eine Warteschlange gelenkt. Existiert keine Realtime-Routine, so wird das Interrupt an den Standard-Linuxkernel weitergereicht. Die entsprechende Routine wird dann ausgeführt um den Interrupt zu behandeln. Unter RTAI werden Realtime-Programme als Module implementiert, was ihre Funktionalität beschränkt, weswegen werden mit RTAI nur die zeitkretischen Teile des Programms implementiert, alles andere wird von Linux durchgeführt. Dies ist möglich, da RTAI dem Linuxkernel erlaubt, alle seine Funktionen und Dienste beizubehalten.

Ereignisse unter RTAI

Beim Eintreten bestimmter Ereignisse startet RTAI benutzerdefinierte Programmteile. Es gibt zwei Arten von Ereignissen (Interrupts):

RTAI Scheduler

Da Linux ein Multitaskingsystem ist dh. mehrere Programme können gleichzeitig ausgeführt werden müssen zur Laufzeit ständig Entscheidungen über die Zuteilung des Prozessors zu den einzelnen Programmen erfolgen. Diese Entscheidungen, die in Abhängigkeit von dem gewünschten Systemverhalten, der eingestellten Prozesszuteilungsstrategie und der dem Betriebssystem bekannten Prozessparameter gefällt werden, übernimmt der Scheduler. Der Scheduler eines Betriebssystems kann abhängig von der Implementierung bei folgenden Aktivitäten aufgerufen werden:

RTAI stellt drei verschiedene Scheduler-Varianten zur Verfügung. Diese unterscheiden sich dadurch, dass sie zum einen für den Einsatz auf Ein-Prozessor-Maschinen und zum anderen für den Einsatz auf Multi-Prozessor-Maschinen spezialisiert sind. In der Kategorie der Multi-Prozessor-Scheduler gibt es weiterhin zwei Varianten, eine in der die Mehr-Prozessor-Maschine als SMP-(Symmetric Multi-Processor) System und eine in der sie als mehrere Einzel-Prozessoren gesehen wird. Benannt sind diese Varianten nach dieser Eigenschaft ( UNI-Prozessor- , SMP- und Multi-Uni-Prozessor-Scheduler). Alle diese Varianten können sowohl im so genannten Oneshot-Timer-Mode (also der Timer läuft einmal ab und unterbricht dann einmal) oder im Periodic-Timer-Mode betrieben werden (in dem der Timer das System periodisch unterbricht).


START



3. Das Klonen eines Projektes mit ELinOS

Bevor wir ein eigene kleine Anwendung unter RTAI betrachten, schauen wir uns an, wie man mit ELinOS v2.2 ein fertiges Projekt klont, realisiert und dann, in einem weiteren Schritt, zu einem anderen Projekt abwandeln kann. Das Projekt, das wir klonen wollen, nennt sich RTAI und findet sich im demos-Ordner von /opt/elinos.

(Hinweis fuer die Umgebung Realzeitlabor: es ist möglich, als normaler User --nicht Root!-- alle Quellen zu kompilieren und eine bootfähige Diskette zu erzeugen. Man muss nach dem Einsatz von Diskettenbefehle nur darauf achten, dass --falls notwendig--, das Diskettenlaufwerk mit dem Befehl umount /media/floppy wieder freigegeben wird. Andernfalls muesste ein neuer User den PC von neuem starten, was etwas aufwendig ist...)


gerd@turing:~/public_html/fh/I-RT04/VL/VL10> /opt/elinos/bin/elinos-cloneproject /opt/elinos/demos/RTAI RTAIDEMO

CLONING PROJECT `RTAIDEMO' FROM `/opt/elinos/demos/RTAI'
========================================================

Checking existing project /opt/elinos/demos/RTAI... ok
Checking new project RTAIDEMO... ok
Cloning project /opt/elinos/demos/RTAI as RTAIDEMO... ok

CONFIGURING PROJECT
===================

Configuration: reading from ./project.config... ok

Current Settings:

   ELINOS_BOARD      = custom
   ELINOS_CPU        = x86
   ELINOS_ARCH       = 386
   ELINOS_LIBC       = libc6
   ELINOS_DOSNAME    = realtime
   ELINOS_BOOT_STRAT = floppy

Please select your board type.
(1)     386_libc5
(2)     486_libc5
(3)     486_FPU_libc5
(4)     386_FPU_libc5
(5)     dilnet_pc_libc5
(6)     386
(7)     486
(8)     486_FPU
(9)     386_FPU
(10)    dilnet_pc
(11)    custom
Board Type [custom]: 486
Project Name (8 characters at most, no blanks) [realtime]: RTAIDEMO
You must now select the boot strategy for your new project:
(1)     floppy -- Floppy Bootstrap
(2)     lilo -- Hard-Disk Bootstrap
(3)     rolo -- x86 ROM Bootstrap with ROLO
(4)     rolo_rawdisk -- ROLO disk boot image (eg. for CompactFlash)
(5)     etherboot -- Diskless Network Bootstrap
(6)     etherboot_multi -- Diskless Network Bootstrap (one Image for Kernel/Root-Filesystem)
Boot Strategy: [floppy]: 1
Please select your kernel source tree. The suggested order is:
(1)     linux-x86-2.4.18
Kernel Source Tree [1]:
Checking Kernel-Source /opt/elinos/linux/linux-x86-2.4.18... ok
Wiping old kernel... ok
Setting up new kernel... ok
Rename mkefs script "realtime.mkefs" to match new project name? [y]: y

Writing file ./project.config... ok
Writing file ELINOS.sh... ok


Configuring Features in /home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO
=========================================================================

*** initializing features
*** feature input complete
*** initializing features
*** feature input complete
*** running feature configuration scripts ...
(prepare) done.
(commit) done.
(mkefs) done.
(kernel) done.
(unkernel) done.
*** merging kernel configuration with feature-config ...

Feature build complete.

----------------------------------------------
Your new project has been set up successfully.
To work on it, type:

  sh# cd "/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO"
  sh# . ELINOS.sh
----------------------------------------------

CLONING DONE.


gerd@turing:~/public_html/fh/I-RT04/VL/VL10> su
Password:
turing:/home/gerd/public_html/fh/I-RT04/VL/VL10 # cd RTAIDEMO/
turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # . ELINOS.sh
STARTING ELINOS SESSION
=======================

Setting up CDK x86_386 for libc6

$ELINOS_BOARD      = 486
$ELINOS_BIN_PREFIX = x86_386
$ELINOS_PROJECT    = /home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO
$ELINOS_DOSNAME    = RTAIDEMO
$CC                = x86_386-gcc
$CXX               = x86_386-g++
$AS                = x86_386-as
$GDB               = x86_386-gdb


turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # l
insgesamt 70
drwxr-xr-x    8 gerd     users         504 2004-12-11 15:47 ./
drwxr-xr-x    4 gerd     users         472 2004-12-11 15:45 ../
drwxr-xr-x    2 gerd     users          48 2004-12-11 15:45 app.rootfs/
drwxr-xr-x    2 gerd     users          48 2004-12-11 15:45 boot/
lrwxrwxrwx    1 gerd     users          32 2004-12-11 15:45 configure -> /opt/elinos/bin/elinos-configure*
-rw-r--r--    1 gerd     users        2732 2004-12-11 15:46 ELINOS.sh
lrwxrwxrwx    1 gerd     users          19 2004-12-11 15:45 elk -> /opt/elinos/bin/elk*
-rw-r--r--    1 gerd     users         380 2004-12-11 15:47 feature.mkefs
drwxr-xr-x    3 gerd     users          72 2004-12-11 15:46 feature.rootfs/
-rw-r--r--    1 gerd     users       12741 2004-12-11 15:46 .features
drwxr-xr-x    2 gerd     users          48 2004-12-11 15:45 kernel.rootfs/
drwxr-xr-x   14 gerd     users         688 2004-12-11 15:47 linux/
-rwxr-xr-x    1 gerd     users       21761 2004-12-11 15:45 makeboot*
-rw-r--r--    1 gerd     users        5085 2004-12-11 15:45 Makefile
-rw-r--r--    1 gerd     users         885 2004-12-11 15:46 project.config
-rw-r--r--    1 gerd     users         191 2004-12-11 15:45 README
-rw-r--r--    1 gerd     users          63 2004-12-11 15:45 RTAIDEMO.mkefs
drwxr-xr-x    4 gerd     users          96 2004-12-11 15:45 src/

(Anmerkung : der nachfolgende Wechsel nach root ist nicht notwendig !)


turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # make boot
Reading feature configuration ... complete
Reading implications from /opt/elinos/elk/valid.elk ... ok.
Reading implications from /home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO/valid.elk ... n/a.
make -C /home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO/linux symlinks clean install
...

Preparing for floppy-boot:
Checking for banner ... installing default banner.
Writing syslinux.cfg ... ok.
Ok.

As a final step to get a bootable floppy disk, please copy the
following files to an empty, MS-DOS formatted floppy:

   cp syslinux.cfg /floppy/syslinux.cfg
   cp banner /floppy/banner
   cp boot/vmlinuz /floppy/linux
   cp RTAIDEMO.tgz /floppy/RTAIDEMO.tgz

To make the floppy bootable, please type:

   /opt/elinos/bin/syslinux /dev/fd0

                             - NOTE -

   You may need root privileges to execute the above commands.

                             - NOTE -

   You may want to customise this script to meet any special
   requirements of your target hardware. For instance, you could
   add the commands neccessary to copy the boot files to a floppy
   disk, or to the download directory of your tftp-server.
   The script is located here:
   /home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO/makeboot

Achtung: Wechsel in den normalen User-Mode!


gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> fdformat /dev/fd0h1440
Doppelseitig, 80 Spuren, 18 Sektoren/Spur, Totale Kapazität: 1440kB.
Formatieren ... Beendet
Überprüfen ... Beendet

gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> mformat a:
gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> mdir
 Volume in drive A has no label
 Volume Serial Number is 7E35-AA2E
Directory for A:/

No files
                          1 457 664 bytes free


gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> mcopy syslinux.cfg banner RTAIDEMO.tgz a:
gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> mcopy boot/vmlinuz a:linux
gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> mdir
 Volume in drive A has no label
 Volume Serial Number is 7E35-AA2E
Directory for A:/

syslinux cfg        78 2004-12-11  16:12
banner            2532 2004-12-11  16:12
RTAIDEMO tgz    848088 2004-12-11  16:12
linux           339599 2004-12-11  16:15
        4 files           1 190 297 bytes
                            266 240 bytes free

gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> /opt/elinos/bin/syslinux /dev/fd0
umount: /media/floppy: Das Gerät wird momentan noch benutzt

Man muss jetzt wiedr in den root-Modus wechseln, um auf das Floppy schreiben zu können (Im Falle des Realzeitlabors ist dies nicht notwendig !).

gerd@turing:~/public_html/fh/I-RT04/VL/VL10/RTAIDEMO> su
Password:
turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # /opt/elinos/bin/syslinux /dev/fd0
mount: /dev/fd0 ist bereits eingehängt oder /tmp/syslinux.mnt.10865.0 wird gerade benutzt
mount: Laut mtab ist /dev/fd0 auf /media/floppy eingehängt

turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # umount /media/floppy
turing:/home/gerd/public_html/fh/I-RT04/VL/VL10/RTAIDEMO # /opt/elinos/bin/syslinux /dev/fd0

Wenn man den PC mit der Diskette gebootet hat, wird man aufgefordert, bestimmte Module zu laden:

insmod rtai
insmod rtai_sched_up
insmod rtai_fifos
insmod rt_process

Dann kann man sein eigenes Demoprogramm starten:

/bin/cscope

Beenden erfolgt über Ctrl-C gefolgt von

rmmod rt_process


START



4. Das Umschreiben eines geklonten Projektes: rtai_hello.c

Nach diesem vorgefertigten Beispiel aus dem demos-Verzeichnis von ELinOS hier eine Abwandlung des Beispiels mit einem eigenen kleinen Modul genannt rtai_hello.c. Man kann daran ersehen, dass sich die RTAI Module genauso wie Standard Linux-Module verhalten.


/***********************
 *

* rtai_hello.c 
*
************************/
	

#include <linux/module.h>
#include <rtai.h>
#include <rtai_fifos.h>

int init_module(void)
{
   rt_printk("Hallo Real Welt...");
   rtai_print_to_screen("Hallo RT nochmal ...");
   return 0;
}
void cleanup_module(void)
{
    rt_printk("Auf wiedersehen...");
}

MODULE_AUTHOR("Mein Name");

MODULE_DESCRIPTION("Mein erstes Realzeit-Programm");

MODULE_LICENSE("GPL");

Dieses Beispiel beschreibt, wie eine Meldung mittels RTAI auf der Konsole ausgegeben werden kann.

Als erstes müssen die notwendigen Headerdateien eingebunden werden (module.h, rtai.h und rati_fifos). Dann muss man in dem Ordner src/rtproc die Quelldateien des ursprünglichen Projektes RTAI löschen und dafür die neue Quelldatei rtai_hello.c einfügen. Schliesslich muss man noch das Makefile ändern. Eine mögliche Version könnte lauten:


Makefile.elinos



all: rtai_hello

LINUX_DIR = $(ELINOS_PROJECT)/linux

MODULE_TARGET = $(ELINOS_PROJECT)/kernel.rootfs/lib/modules/$(KERNELRELEASE)

CFLAGS = -I$(LINUX_DIR)/include -I$(LINUX_DIR)/include/linux -I$(LINUX_DIR)/drivers/rtai/include -O2 -Wall

CFLAGS_USER_APP = -O2 -Wall

rtai_hello: rtai_hello.c
	$(CC) -D__KERNEL__ -DMODULE $(CFLAGS) -c $<
	$(LD) -r -o $@ $@.o -static -lm

install: rtai_hello
	mkdir -p $(MODULE_TARGET)/rtai
	cp rtai_hello $(MODULE_TARGET)/rtai/$<.o
	mkdir -p $(ELINOS_PROJECT)/app.rootfs/bin

clean:
	rm -f *~ *.rtai_hello

distclean:

Die Variablen in diesem Makefile werden durch die vorausgehende Initialisierung mit dem Befehl . ELINOS.sh gesetzt. So hat z.B. die Variable MODULE_TARGET im Ausdruck $(MODULE_TARGET) in unserem Beispiel hat den Wert 'kernel.rootfs/lib/modules/2.4.18'

Die Variable $< hat die Bedeutung, dass der Wert der ersten Voraussetzung eingesetzt werden soll, das ist hier rtai_hello.c

Die Variable $@ hat die Bedeutung, dass der Dateiname des ersten Zieles eingesetzt werden soll, das ist hier rtai_hello

Sehr wichtig in diesem Makefile ist der Befehl install:, da durch diesen Befehl das kompilierte Modul zu den Modulen von rtai hinzugefügt wird.

Der weitere Ablauf ist wie bei dem vorausgehenden Beispiel, nur mit anderen Projektnamen.

Nach dem Booten der Diskette lautet die Befehlssequenz für das Laden der Module wie folgt:

insmod rtai
insmod rtai_sched_up
insmod rtai_fifos
insmod rtai_hello

Man sieht, dass jetzt das eigene Modul wie ein RTAI-Modul geladen wird. Die Printouts erscheinen beim Ablauf auf dem Bildschirm.

Man entfernt dieses Modul wieder durch:

rmmode rtai_hello


START



5. Das Demoprojekt cscope

Das folgende Beispiel ist etwas ausführlicher (entnommen aus dem Sysgo-Usermanual; in einfacherer Form auch im DIAPM RTAI - Beginner's Guide (Weblocation), (Lokal)). Es besteht aus einem Makefile, den beiden init und cleanup-Modulen sowie einer Hilfunktion. Dieses Beispiel soll analysiert werden. Im Anschluss werden die allgemeinen Strukturen von RTAI (Kommunikation und Scheduling) noch etwas allgemeiner dargestellt und mit dem bisherigen abstrakten Modell verglichen.


Makefile.elinos



all: rt_process cscope

LINUX_DIR = $(ELINOS_PROJECT)/linux

MODULE_TARGET = $(ELINOS_PROJECT)/kernel.rootfs/lib/modules/$(KERNELRELEASE)

CFLAGS = -I$(LINUX_DIR)/include -I$(LINUX_DIR)/include/linux -I$(LINUX_DIR)/drivers/rtai/include -O2 -Wall

ifeq ("$(LINUX_ARCH)", "ppc")
	CFLAGS += -I$(LINUX_DIR)/arch/ppc
endif
CFLAGS_USER_APP = -O2 -Wall
XLIBS  = -I/usr/X11R6/include -L/usr/X11R6/lib


rt_process: rt_process.c
	$(CC) -D__KERNEL__ -DMODULE $(CFLAGS) -c $<
	$(LD) -r -o $@ $@.o -static -lm

install: rt_process cscope
	mkdir -p $(MODULE_TARGET)/rtai
	cp rt_process $(MODULE_TARGET)/rtai/$<.o
	mkdir -p $(ELINOS_PROJECT)/app.rootfs/bin
	cp cscope $(ELINOS_PROJECT)/app.rootfs/bin/.

xscope: scope.c sin.c
	$(CC) -DX11 $(CFLAGS_USER_APP) $^ -o $@ $(XLIBS) -lforms -lX11 -lm -static

cscope: scope.c sin.c
	$(CC) $(CFLAGS_USER_APP) $^ -o $@ -lm


clean:
	rm -f *~ *.o cscope xscope rt_process

distclean:


rt_process.c (mit init und cleanup; Hilfsfunktion singen0()



// rt_process.c

#include <asm/system.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>


/* timer period length in ns  */
#define TICK_PERIOD   10000000
/* 0 is highest priority, RT_LOWEST_PRIORITY is lowest */
#define TASK_PRIORITY 1
#define USES_FPU      0
#define STACK_SIZE    16384

/* number of fifo device (/dev/rtfX) */
#define FIFO          0
/* size of fifo in bytes */
#define FIFO_SIZE     16384


static RT_TASK rt_task0;


/* the realtime task */
static void sin_gen0(int notused)
{
    unsigned long now, last, nanoseconds;

    nanoseconds = 0;
    last = rt_get_cpu_time_ns();

    while (1)
    {
	now = rt_get_cpu_time_ns();
	nanoseconds = nanoseconds + now - last;
	while (nanoseconds >= 1000000000)
		nanoseconds -= 1000000000;
	last = now;

	/* put current nanoseconds into fifo */
	rtf_put(FIFO, &nanoseconds, sizeof(nanoseconds));

        /* suspend task util next period */
        rt_task_wait_period();
    }
}



/* called when module is inserted */
static int __init init_rt_task0(void)
{
    RTIME tick_period;

#if !defined(CONFIG_PPC)
    /* set periodic mode for timer */
    rt_set_periodic_mode();
#else
    /* on PowerPC we use oneshot mode to reduce system load */
    rt_set_oneshot_mode();
#endif
    /* initializing the task */
    rt_task_init(&rt_task0, sin_gen0, 0, STACK_SIZE, TASK_PRIORITY, USES_FPU, 0);
    /* creating fifo */
    rtf_create(FIFO, FIFO_SIZE);
    /* start timer */
    tick_period = start_rt_timer(nano2count(TICK_PERIOD));
    /* the realtime process should be choosen by the scheduler periodically */
    rt_task_make_periodic(&rt_task0, rt_get_time() + tick_period, tick_period);
    return 0;
}



/* called when module is removed */
static void __exit cleanup_rt_task0(void)
{
    /* kill timer */
    stop_rt_timer();
    /* kill fifo */ 
    rtf_destroy(FIFO);
    /* kill task */
    rt_task_delete(&rt_task0);

    return;
}

module_init(init_rt_task0);
module_exit(cleanup_rt_task0);


scope.c



// scope.c

#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include <signal.h>

#ifdef X11
/* using "libforms" */
#include <forms.h>

/* scaling factor for the fixed window size */
#define WIN_SIZE 15
#define CANCEL ((obj != exitbut) && (!canceled))

FL_FORM *form;
FL_OBJECT *chartobj, *sinobj, *exitbut, *stepobj;


void create_form_form(void)
{
  FL_OBJECT *obj;


  form = fl_bgn_form(FL_NO_BOX,43*WIN_SIZE,23*WIN_SIZE);
  obj = fl_add_box(FL_BORDER_BOX,0,0,43*WIN_SIZE,32*WIN_SIZE,"");
  chartobj = obj = fl_add_chart(FL_LINE_CHART,2*WIN_SIZE,7*WIN_SIZE,39*WIN_SIZE,14*WIN_SIZE,"");
  fl_set_object_dblbuffer(obj,1);

  /* create exit button */
  exitbut = obj = fl_add_button(FL_NORMAL_BUTTON,15*WIN_SIZE,2*WIN_SIZE,14*WIN_SIZE,3*WIN_SIZE,"Exit");
    fl_set_object_boxtype(obj,FL_BORDER_BOX);
   fl_end_form();
}
#else
#define CANCEL (!canceled)
#endif

int canceled=0;

double sinus(double x);

void sigint_handler(int i)
{
  printf("Caught signal %i\n",i);
  canceled=1;
}

int main(int argc, char *argv[])
{
   int i;
#ifdef X11
   FL_OBJECT *obj;
#else
   int v;
#endif
   struct sched_param p;
   int fifo;
   long time_value;
   float sin_value;
   char *filename;

   signal(SIGINT, sigint_handler);
   signal(SIGTERM, sigint_handler);

   p.sched_priority=5;
   if ((i=sched_setscheduler(0, SCHED_FIFO, &p))) {
     perror("SetScheduler failed");
     return 1;
   }

   /* open FIFO for reading */
   if ((argc > 1) && (argv[1][0] != '-')) {
     filename = argv[1];
     fifo=open(filename, O_RDONLY);
   } else {
     /* try to open /dev/rtf0, then /dev/rtf/0 in case devfs in configured */
     filename = "/dev/rtf0 or /dev/rtf/0";
     if((fifo=open("/dev/rtf0", O_RDONLY)) == -1)
       fifo=open("/dev/rtf/0", O_RDONLY);
   }

   if (fifo == -1)
     {
       fprintf(stderr,"\nunable to open device %s (%s)\n\n",filename,strerror(errno));
       exit(1);
     }

#ifdef X11
   /* initializing scope window */
   fl_flip_yorigin();
   fl_initialize(&argc, argv, "Scope", 0, 0);
   create_form_form();
   fl_set_chart_bounds(chartobj,-1.5,1.5);
   fl_set_chart_maxnumb(chartobj,80);
   fl_set_chart_autosize(chartobj,0);
   fl_show_form(form,FL_PLACE_CENTER,FL_FULLBORDER,"Scope");
#endif

    do
    {
      /* reading time values from fifo */
     read(fifo, &time_value, sizeof(time_value));
     /* calculate sinus */
     sin_value = sinus(2*M_PI*1*time_value/1E9);
#ifdef X11
      /* insert value into diagramm */
     fl_insert_chart_value(chartobj,1,sin_value,"",1);
      /* update diagramm */
     obj = fl_check_forms();
#else
     v=(int)(sin_value*5.0)+5;
     for (i=0;i<v;i++) printf(" ");
     printf("*\n");
#endif
    }
    /* exit button pressed ? */
    while (CANCEL);
#ifdef X11
    fl_finish();
#endif
    close(fifo);
    return(0);
}


sin.c



// sin.c

#include <stdio.h>
#include <stdlib.h>

#ifndef M_PI
#  define M_PI           3.14159265358979323846  /* pi */
#endif
#ifndef M_PI_2
#  define M_PI_2         1.57079632679489661923  /* pi/2 */
#endif

double sinus (double x)
{
  double acc = x;
  double sum = 0;
  int j;
  /* factorial of first N numbers */
  static double const fac[] = { 1.0, 6.0, 120.0, 5040.0, 362880.0 };
  double mult = 1.0;
  static double const pi2 = 2.0 * M_PI;    /* 2pi */
  static double const pi32 = 3.0 * M_PI_2; /* 3/2 pi */

  /* get x into [0, 2pi[ */
  while (x >= pi2) x -= pi2;

  /* get x into the first quadrant */
  if (x > pi32) {
    x = 2 * M_PI - x;
    mult = -1.0;
  } else if (x > M_PI) {
    x = x - M_PI;
    mult = -1.0;
  } else if (x > M_PI_2) {
    x = M_PI - x;
  }


  /* initialize for taylor series */
  sum = 0;  /* partial sum of taylor series */
  acc = x;  /* x^(2k + 1) */
  

  /* now the first components of taylor series */
  for (j = 0; j < 5; j++) {
    sum += acc / fac[j];
    acc *= x * x * (-1.0);
  }

  return mult * sum;

}


START



6. Testfragen und Übungsaufgaben


  1. Wie interagieren RTAI und Linux?

  2. Welche Stellung hat RTAI gegenüber der Hardware?

  3. Welche Art von Ereignissen gibt es aus der Sicht von RTAI?

  4. Wie werden Ereignisse unter RTAI verwaltet? Welche Art von Scheduler gibt es?

  5. In welchem Sinne kann man das Werkzeug ELinOS für die Entwicklung von RTAI-Anwendungen nutzen?


START