RTLinux easy but RT hard.

I wrote a chapter for an academic book recently and the publisher sent me a “copyright assignment” form ( don’t even start) that asked me, among other things, to provide a warranty that it was perfectly safe to use the methods I described. Well, to be plain – it’s not. Real-time software gives you a plethora of opportunities for causing damage (there was that programmer in Jersey, not using RTLinux, who discovered his mistake when the placer robot started tossing 50Kg blocks of steel at him). So please let’s not have a “real-time programming for dummies” anytime soon. dummies But it’s a lot easier to write correct real-time software, even for smart and well educated people, if the operating system is not making things unnecessarily complex. In fact, that’s a good description of our mission at FSMLabs: rooting out and destroying unnecessary complexity in real-time systems. The PSDD system by Barabanov is pretty impressive at that, but here’s how to write a simple data acquisition loop in vanilla RTLinux courtesy of the “main” system mostly due to Cort Dougan. This is a quantum jump over the original “Linux module” stuff we had in the old days and it opens up many new improvements. Note that standard out even works! Proof that “simple” and “raw” are different.

The basic loop looks like”while(running){ input data; forward data; wait until next period;}. A RTLinuxPro application to implement this consists of a Linux/BSD executable dot-rtl program and some Linux or BSD post processing. The dot-rtl program usually has the form ” thread; main(){}” where the main routine initializes data and starts the thread. A simple version would output to standard out. Then you could use a command line “myprogram.rtl > logfile” or “myprogram.rtl | postprocess”to log or postprocess the data. Here is an example running at a period of 200 microseconds with data consisting of a single 32bit value and a count that can be used as a kind of timestamp. Just add some error checking and go.

#include
#include
#include

pthread_t thread;
int running = 1;
extern void get_input(int *);

void *loop(void *t)
{
unsigned int data;
unsigned long count = 0;
struct timespec next;
rtl_clock_gettime(CLOCK_REALTIME, &next);

while ((volatile int) running) {
get_input(&data); //you write this one.
printf("%ul %un", count, data);
count++;
timespec_add_ns(&next, 500 * 1000);
rtl_clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, NULL);
}
return NULL;
}

int main(void)
{
rtl_pthread_create(&thread, NULL, loop, (void *) 0);
rtl_main_wait(); //wait for stop from user
running = 0; // not really necessary, but it seems cleaner to me.
rtl_pthread_cancel(thread);
rtl_pthread_join(thread, NULL);
return 0;

}