|
I-RT04 REALZEITSYSTEME WS04
|
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.
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).
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.
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):
Intern: Zeitgesteuerte Interrupts (Timer Interrupts)
Extern: externe 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).
Uni-Prozessor-Scheduler: Dieser Scheduler ist recht simpel. Er besteht aus mehreren Listen mit verschiedenen Prioritäten, welche er linear durchläuft und zur Vermeidung von Prioritätenumkehr das Priority-Inhartitance-Protocol nutzt. In dieser Konfiguration ist Linux ein Echtzeit-Prozess wie jeder andere, allerdings mit geringster Priorität.
SMP-Scheduler: Der SMP-Scheduler unterscheidet sich vom Uni-Prozessor-Scheduler dadurch, dass er die Prozesse auf die zur Verfügung stehenden Prozessoren verteilen kann. Das ermöglicht ein paar zusätzliche Dienste, so können zum Beispiel die Paare CPU,Prozess) und (CPU,IRQ) konkret zugeordnet werden. Außerdem können die Timer des APIC (Advanced Programmable Interrupt Controller) der SMP-Architektur genutzt werden.
Multi-Uni-Prozessor Scheduler: Wie der Name schon sagt, sieht dieser Scheduler die SMP-Maschine als eine Ansammlung von Einzel-Prozessor-Maschinen, was bedeutet, dass jeder Prozessor seine Timer unabhängig von den anderen programmieren kann. Also können die Timer-Modi periodic und oneshot abhängig von der CPU verschieden sein.
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
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
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; }
Wie interagieren RTAI und Linux?
Welche Stellung hat RTAI gegenüber der Hardware?
Welche Art von Ereignissen gibt es aus der Sicht von RTAI?
Wie werden Ereignisse unter RTAI verwaltet? Welche Art von Scheduler gibt es?
In welchem Sinne kann man das Werkzeug ELinOS für die Entwicklung von RTAI-Anwendungen nutzen?