RTAI: Hard Real Time Serial Port (RS232) Example with RTDM (Real Time Driver Model)
This is a simple RTAI 3.3 hard real time serial port example. It will send some characters over the serial port,
and if something is received, those characters are displayed.
Use a simple RS232 dummy adapter (loopback plug): Connect PIN 2 (RX) to PIN 3 (TX) (9-pin SUB-D RS232 connector on your machine),
or if you use a 25-pin SUB-D connector: Connect PIN 3 (RX) to PIN 2 (TX).
Tested on RTAI 3.3 test1 on kernel 2.4.32 and 2.6.14.3 with the corresponding ADEOS IPIPE patches.
Also tested on RTAI 3.4 (volcano CVS after test1 was released)
Also see:
RTAI serial port example (classic driver)
Xenomai: Hard Real Time Serial Port (RS232) Example with RTDM (Real Time Driver Model)
Serial (RS232) Port Pins and Registers
RTAI versus Xenomai comparison on the Serial Port Example with RTDM (Real Time Driver Model)
Compile the example with the Makefile, load the RTAI modules with loadmods.sh
and run "rt_serial_uprog". Make sure you have the loopback plug hooked up on the serial port,
otherwise you won't see any characters received.
You'll see this on your console:
# ./loadmods.sh
# ./rt_serial_uprog
rt_serial_uprog: read-file opened
rt_serial_uprog: read-config written
rt_serial_uprog: read-task created
rt_serial_uprog: write-task created
write_task: rt_dev_write written=17 sz=17
read_task : rt_dev_read=CAPTAIN WAS HERE
write_task: rt_dev_write written=17 sz=17
read_task : rt_dev_read=CAPTAIN WAS HERE
If you have problems, check the Xenomai - RTAI RTDM serial port troubleshooting howto.
rt_serial_uprog.c
// Modified version of showroom/rtdm/ftest.c
// derived from:
// http://www.rts.uni-hannover.de/mitarbeiter/kiszka/rtaddon/
// RTDM documentation:
// http://download.gna.org/xenomai/documentation/html/api/group__rtserial.html
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <rtai_lxrt.h>
#include <rtdm/rtserial.h>
#define LOG_PREFIX "rt_serial_uprog: "
#define WTASK_PREFIX "write_task: "
#define RTASK_PREFIX "read_task : "
#define RTSER_FILE "rtser0"
#define READ_FILE "rtser1"
int timer_started = 0;
int my_fd = -1;
#define STATE_FILE_OPENED 1
#define STATE_TASK_CREATED 2
unsigned int my_state = 0;
RT_TASK *maint;
// --s-ms-us-ns
RTIME write_task_period_ns = 1000000000llu;
RT_TASK *write_task;
RT_TASK *read_task;
static pthread_t write_thr, read_thr;
static const struct rtser_config ser_config = {
0xFFFF, /* config_mask */
9600, /* baud_rate */
RTSER_DEF_PARITY, /* parity */
RTSER_DEF_BITS, /* data_bits */
RTSER_DEF_STOPB, /* stop_bits */
RTSER_DEF_HAND, /* handshake */
RTSER_DEF_FIFO_DEPTH, /* fifo_depth*/
RTSER_DEF_TIMEOUT, /* rx_timeout */
RTSER_DEF_TIMEOUT, /* tx_timeout */
RTSER_DEF_TIMEOUT, /* event_timeout */
RTSER_RX_TIMESTAMP_HISTORY, /* timestamp_history */
RTSER_EVENT_RXPEND /* event mask */
};
static int close_file(int fd, char *name) {
int ret, i = 0;
do {
i++;
ret = rt_dev_close(fd);
switch(-ret){
case EBADF: printf(LOG_PREFIX
"%s -> invalid fd or context\n",name);
break;
case EAGAIN: printf(LOG_PREFIX
"%s -> EAGAIN (%d times)\n",name,i);
rt_sleep(nano2count(50000)); // wait 50us
break;
case 0: printf(LOG_PREFIX "%s -> closed\n",name);
break;
default: printf(LOG_PREFIX "%s -> ???\n",name);
break;
}
} while (ret == -EAGAIN && i < 10);
return ret;
}
void cleanup_all(void)
{
if (my_state & STATE_FILE_OPENED) {
close_file( my_fd, READ_FILE" (read)");
my_state &= ~STATE_FILE_OPENED;
}
if (my_state & STATE_TASK_CREATED) {
printf(LOG_PREFIX "delete write_task\n");
rt_task_delete(write_task);
printf(LOG_PREFIX "delete read_task\n");
rt_task_delete(read_task);
my_state &= ~STATE_TASK_CREATED;
}
if (timer_started) {
printf(LOG_PREFIX "stop timer\n");
stop_rt_timer();
}
printf("end cleanup\n");
}
void catch_signal(int sig) {
pthread_join(write_thr, NULL);
pthread_join(read_thr, NULL);
cleanup_all();
rt_task_delete(maint);
printf(LOG_PREFIX "exit\n");
return;
}
void write_task_proc(void *arg) {
int ret;
ssize_t sz = sizeof(RTIME);
ssize_t written = 0;
unsigned char buf[17] = "CAPTAIN WAS HERE\0";
write_task = rt_task_init_schmod(nam2num("WRTSK"),
2, 0, 0, SCHED_FIFO, 0xF);
poll(0, 0, 10);
mlockall(MCL_CURRENT | MCL_FUTURE);
rt_make_hard_real_time();
rt_task_make_periodic_relative_ns(NULL, 0,
write_task_period_ns);
while (1) {
ret = rt_task_wait_period();
if (ret) {
printf(WTASK_PREFIX "error while rt_task_wait_period, code %d\n",ret);
goto exit_write_task;
}
sz = sizeof(buf);
written = rt_dev_write(my_fd, &buf, sizeof(buf));
printf(WTASK_PREFIX "rt_dev_write written=%d sz=%d\n", written, sz);
if (written != sz ) {
if (written < 0 ) {
printf(WTASK_PREFIX "error while rt_dev_write, code %d\n",written);
} else {
printf(WTASK_PREFIX "only %d / %d byte transmitted\n",
written, sz);
}
goto exit_write_task;
}
}
exit_write_task:
if (my_state & STATE_FILE_OPENED) {
if (!close_file( my_fd, RTSER_FILE " (write)")) {
my_state &= ~STATE_FILE_OPENED;
}
}
rt_make_soft_real_time();
rt_task_delete(write_task);
printf(WTASK_PREFIX "exit\n");
}
void read_task_proc(void *arg) {
int ret;
ssize_t sz = sizeof(RTIME);
ssize_t red = 0;
struct rtser_event rx_event;
unsigned char buf[17];
read_task = rt_task_init_schmod(nam2num("RDTSK"), 1, 0, 0,
SCHED_FIFO, 0xF);
poll(0, 0, 10);
mlockall(MCL_CURRENT | MCL_FUTURE);
rt_make_hard_real_time();
while (1) {
/* waiting for event */
ret = rt_dev_ioctl(my_fd, RTSER_RTIOC_WAIT_EVENT, &rx_event );
if (ret) {
printf(RTASK_PREFIX "error while RTSER_RTIOC_WAIT_EVENT, code %d ENOSYS=%d\n",
ret, ENOSYS);
goto exit_read_task;
}
sz = sizeof(buf);
red = rt_dev_read(my_fd, &buf, sizeof(buf));
if (red == sz ) {
printf(RTASK_PREFIX "rt_dev_read=%s\n",buf);
} else {
if (red < 0 ) {
printf(RTASK_PREFIX "error while rt_dev_read, code %d\n",red);
} else {
printf(RTASK_PREFIX "only %d / %d byte received \n",red,sz);
}
goto exit_read_task;
}
}
exit_read_task:
if (my_state & STATE_FILE_OPENED) {
if (!close_file( my_fd, READ_FILE " (read)")) {
my_state &= ~STATE_FILE_OPENED;
}
}
rt_make_soft_real_time();
rt_task_delete(read_task);
}
int main(int argc, char* argv[]) {
int ret = 0;
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
signal(SIGKILL, catch_signal);
/* no memory-swapping for this programm */
maint = rt_task_init_schmod(nam2num("MAIN"), 3, 0, 0,
SCHED_FIFO, 0xF);
rt_set_oneshot_mode();
start_rt_timer(0);
/* open rtser1 */
my_fd = rt_dev_open(RTSER_FILE, 0);
if (my_fd < 0) {
printf(LOG_PREFIX "can't open %s (read)\n", RTSER_FILE);
goto error;
}
my_state |= STATE_FILE_OPENED;
printf(LOG_PREFIX "read-file opened\n");
/* writing read-config */
ret = rt_dev_ioctl(my_fd, RTSER_RTIOC_SET_CONFIG, &ser_config);
if (ret) {
printf(LOG_PREFIX "error while rt_dev_ioctl, code %d\n",ret);
goto error;
}
printf(LOG_PREFIX "read-config written\n");
/* create read_task */
pthread_create(&read_thr, NULL, (void *)read_task_proc, NULL);
my_state |= STATE_TASK_CREATED;
printf(LOG_PREFIX "read-task created\n");
/* create write_task */
pthread_create(&write_thr, NULL, (void *)write_task_proc, NULL);
my_state |= STATE_TASK_CREATED;
printf(LOG_PREFIX "write-task created\n");
pause();
return 0;
error:
cleanup_all();
return ret;
}
Makefile
TARGET = rt_serial_uprog
ifeq ($(RTAIDIR),)
RTAIDIR = /usr/realtime
endif
RTAI_LIB_DIR = $(shell $(RTAIDIR)/bin/rtai-config --library-dir)
CC = $(shell $(RTAIDIR)/bin/rtai-config --cc)
CFLAGS = -g -I $(RTAIDIR)/include -lpthread -llxrt -lrtdm -L $(RTAI_LIB_DIR) -Wall -O2
all: $(TARGET)
$(TARGET): $(TARGET).c
clean:
$(RM) $(TARGET)
loadmods.sh
#!/bin/sh
TMP=$PWD
cd /usr/realtime/modules/
setserial /dev/ttyS0 uart none
setserial /dev/ttyS0 uart 16550A
setserial /dev/ttyS0 uart none
MODULEEXTENSION="o"
insmod ./rtai_hal.$MODULEEXTENSION
insmod ./rtai_lxrt.$MODULEEXTENSION
insmod ./rtai_sem.$MODULEEXTENSION
insmod ./rtai_rtdm.$MODULEEXTENSION
insmod ./rtai_16550A.$MODULEEXTENSION ioaddr=0x3f8 irq=4 start_index=0
cd $TMP
Last-Modified: Thu, 27 Jul 2006 19:31:58 GMT