RTAI/fusion Pipe (FIFO) Kernel Module Example
Also see Porting software from RTAI/fusion to Xenomai
This is a simple RTAI/fusion hard real time pipe (FIFO) example (based on the snippets "showroom" in
[fusion-dir]/skins/rtai/snippets/pipe.c). pipe.c is the kernel module, which opens the pipe (FIFO)
/dev/rtf0 for reading and writing in kernel space. user.c is the user-space program, which also reads
and writes from/to the pipe.
Compile the program "pipe.c" and "user.c" with "make" (Makefile below).
Run "user" and - in another shell - load the fusion modules with "loadmods.sh"
and the pipe kernel module with "insmod ./pipe.ko".
# ./user
read from pipe: Hello
written string 'World' - see kernel log
In the kernel log you'll see:
Jul 31 21:09:52 muon kernel: INIT DONE
Jul 31 21:09:52 muon kernel: received msg> World, size=6
Jul 31 21:10:00 muon kernel: CLEANUP DONE
If you get a compilation error like this
timer.c: In function `main':
*timer.c:45: warning: implicit declaration of function `rt_task_spawn'
/tmp/ccIQ6xk6.o(.text+0x129): In function `main':
: undefined reference to `rt_task_spawn'
collect2: ld returned 1 exit status*
make: *** [timer] Error 1
you need to upgrade to a recent version of RTAI/fusion (0.8.3 as of writing this).
rt_task_spawn was added in version 0.7.3.
rt_task_spawn() is actually a combination of rt_task_create() and rt_task_start().
The warnings about the undefined symbols can be ignored. The symbols will resolve as soon as the
fusion kernel modules are loaded with "loadmods.sh":
# make
make -C /lib/modules/2.6.12.3-adeos-fusion/build SUBDIRS=/home/fusion/kernelpipe modules
make[1]: Entering directory `/usr/src/linux-2.6.12.3-fusion'
CC [M] /home/fusion/kernelpipe/pipe.o
Building modules, stage 2.
MODPOST
*** Warning: "rt_task_delete" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_delete" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_task_start" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_task_create" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_create" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_free" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_receive" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_send" [/home/fusion/kernelpipe/pipe.ko] undefined!
*** Warning: "rt_pipe_alloc" [/home/fusion/kernelpipe/pipe.ko] undefined!
LD [M] /home/fusion/kernelpipe/pipe.ko
make[1]: Leaving directory `/usr/src/linux-2.6.12.3-fusion'
gcc -o user user.c -I/usr/realtime/include
pipe.c
#include <linux/module.h>
#include <rtai/task.h>
#include <rtai/pipe.h>
#define PIPE_MINOR 0
#define TASK_PRIO 2 /* Highest RT priority */
#define TASK_MODE T_FPU|T_CPU(0) /* Uses FPU, bound to CPU #0 */
#define TASK_STKSZ 4096 /* Stack size (in bytes) */
RT_TASK task_desc;
RT_PIPE pipe_desc;
void task_body (void *cookie) {
RT_PIPE_MSG *msgout, *msgin;
int len = sizeof("Hello");
/* Get a message block of the right size in order to initiate the
message-oriented dialog with the user-space process. Sending a
continuous stream of bytes is also possible using
rt_pipe_stream(), in which case no message buffer needs to be
preallocated. */
msgout = rt_pipe_alloc(len);
if (msgout) {
// Send prompt message "Hello"
strcpy( P_MSGPTR(msgout), "Hello");
//rt_pipe_send(&pipe_desc, msgout, len, P_NORMAL);
if (rt_pipe_send(&pipe_desc, msgout, len, 0) != len) {
rt_pipe_free(msgout);
}
// Then wait for the reply string "World":
rt_pipe_receive(&pipe_desc, &msgin, TM_INFINITE);
printk("received msg> %s, size=%d\n",P_MSGPTR(msgin),P_MSGSIZE(msgin));
// Free the received message buffer.
rt_pipe_free(msgin);
} else {
printk("ERROR: rt_pipe_alloc\n");
}
}
int __init init_module (void) {
int err;
err = rt_pipe_create(&pipe_desc, "pipetest", PIPE_MINOR);
if (!err) {
err = rt_task_create(&task_desc, "MyTaskName", TASK_STKSZ, TASK_PRIO, TASK_MODE);
if (!err) {
rt_task_start(&task_desc, &task_body, NULL);
} else {
printk("ERROR: cannot create task\n");
return 0;
}
/* // since fusion 0.7.3 you can also use rt_task_spawn
err = rt_task_spawn(&task_desc, "MYTask", TASK_STKSZ, TASK_PRIO, 0, &task_body, NULL);
if (err) {
printk("error rt_task_spawn\n");
return 0;
}
*/
} else {
printk("ERROR: cannot create pipe\n");
}
printk("INIT DONE\n");
return 0;
}
void __exit cleanup_module (void) {
rt_pipe_delete(&pipe_desc);
rt_task_delete(&task_desc);
printk("CLEANUP DONE\n");
}
MODULE_LICENSE("GPL");
user.c
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <rtai/pipe.h>
#define PIPE_MINOR 0
int pipe_fd;
int main (int argc, char *argv[]) {
char devname[32], buf[16];
sprintf(devname, "/dev/rtp%d", PIPE_MINOR);
pipe_fd = open(devname, O_RDWR);
if (pipe_fd < 0) {
printf("cannot open pipe %s\n", devname);
exit(1);
}
read(pipe_fd, buf, sizeof(buf));
printf("read from pipe: %s\n", buf);
write(pipe_fd, "World", sizeof("World"));
printf("written string 'World' - see kernel log\n");
close(pipe_fd);
}
loadmods.sh
#!/bin/sh
TMP=$PWD
cd /usr/realtime/modules/
insmod ./rtai_hal.ko
insmod ./rtai_nucleus.ko
insmod ./rtai_native.ko
cd $TMP
Makefile
obj-m := pipe.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
EXTRA_CFLAGS := -I/usr/realtime/include -I/usr/include/
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
gcc -o user user.c -I/usr/realtime/include
Last-Modified: Sat, 04 Feb 2006 16:06:01 GMT