[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Blocking read from FIFO in Linux app?



I installed RTLinux 3.0 on Kernel 2.2.18 on a dual processor PIII 500MHz. All I
need is a 60Hz signal to a Linux app. I originally tried modifying the Kernel Hz
from 100 to 960 but for some reason there were a tremendous amount of jitter
whereas 100Hz was fairly stable.

For my second attempt, I installed RTL 3.0 and cobbled up a pair of programs
from the examples. In my test program everything is fine and the jitter is quite
low no matter what I try to peturb it. When I try to use the read in a large Ada
program it works for a while and then I start getting zero bytes back from the
FIFO sometimes instead of blocking until the FIFO is non empty. I put in code to
read the FIFO again if the read returns zero bytes but instead of blocking on
the FIFO my CPU utilization is 100%.

I like having the FIFO return a structure which is the tic count and the elapsed
time from the RDTSC instruction because it allows me to detect frame overruns
but I could use a semaphore if anyone has a reliable example.

Jon Clifton

    

all: rtlinux_mod.o linux_app

include ../../rtl.mk

linux_app: linux_app.c
	$(CC) ${USER_CFLAGS} ${INCLUDE} -Wall -O2 -o linux_app linux_app.c

test: all
	@ -/sbin/rmmod rtlinux_mod
	(cd ../../; scripts/rmrtl)
	(cd ../../; scripts/insrtl)
	@/sbin/insmod -v rtlinux_mod.o
	@./linux_app

stop_test:
	@ -/sbin/rmmod rtlinux_mod
	-/sbin/rmmod rtl_fifo
	-/sbin/rmmod rtl_sched
	-/sbin/rmmod rtl_time

clean:
	rm -f *.o linux_app

include $(RTL_DIR)/Rules.make

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

#define NANOSECONDS_PER_TICK (double)((double)1000.00/(double)500.00) 
int main(){
	int fd,count;
	int tics=0;
	struct { int count; unsigned int d;}D;
	double f;
	double sum=0.0;
	if( (fd = open("/dev/rtf0",O_RDONLY) ) < 0 ){
		perror("Can't open fifo");
		exit(-1);
	}
	read(fd,&D,sizeof(D));
	count = D.count;
	while( (read(fd,&D,sizeof(D))  == sizeof(D))){
		f = (double)D.d;
		f = ((f) * NANOSECONDS_PER_TICK)/1000;
                sum+=f;
		tics++;
		printf("Delay was %f microseconds, avg=%f, D={%8d, %08x}\n",
			f,sum/(double)tics, D.count, D.d);
		if(count && (count+1 != D.count))
			printf("Dropped a packet at %d ",count);
		count = D.count;
	}
	return 0;
}

#include <rtl.h>
#include <rtl_fifo.h>
#include <time.h>
#include <rtl_sched.h>
#include <rtl_sync.h>
#include <pthread.h>
#include <posix/unistd.h>

#define FRAME_INTERVAL 16695149LL /* fudged 16.67ms */
#define FIFO_SIZE 4000

pthread_t thread;
int fd;
int stop = 0;
static void copy_device_data(unsigned int *);

void *start_routine(void *arg){
	struct sched_param p;
	struct {int i; unsigned int d; }D = {0,0};

	p.sched_priority=1;
	pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
	pthread_make_periodic_np (pthread_self(), 
		clock_gethrtime(CLOCK_RTL_SCHED),
		FRAME_INTERVAL);
	copy_device_data(&D.d);

	while(!stop){
		pthread_wait_np();
		copy_device_data(&D.d);
		D.i++;
		/* ignore write fails, we just drop the data */
		write(fd,&D,sizeof(D));
	}
	return 0;
}
int init_module(void){
	
	rtf_destroy(0);
        rtf_create(0,FIFO_SIZE);
	if ( (fd = open("/dev/rtf0",O_WRONLY | O_NONBLOCK )) < 0)
	{
		rtl_printf("rtlinux_mod cannot open fifo\n");
		rtl_printf("Error number is %d\n",errno);
		return -1;
	}
	return( pthread_create(&thread,NULL,start_routine,0));
}

void cleanup_module(void){ 
	stop = 1;
	close(fd);
	rtf_destroy(0);
	pthread_delete_np(thread);
	return;
}

static void copy_device_data(unsigned int *x)
{
	static int last=0;
	int d;
	rdtscl(d);
	*x= (d - last);
	last = d;
	return;
}


#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define CPU_MHz 500.00L
#define NANOSECONDS_PER_TICK (double)((double)1000.00/(double)CPU_MHz) 
//#define DEBUG

int rtl_wait(void) {
          //(int * tics, double * delta_t){
	static int firstpass=1;
	static int fd;
	static int rtl_count;
	static int n=0;
	static int nbytes=0;
	static double sum;
	struct { int rtl_count; unsigned int d;}D;
	double f;

	if (firstpass) {
		if( (fd = open("/dev/rtf0",O_RDONLY) ) < 0 ){
			perror("Can't open fifo");
			exit(-1);
		}
		firstpass=0;
		n=0;
		sum=0.0;
		read(fd,&D,sizeof(D));
		rtl_count = D.rtl_count;
	}
	while (0 ==(nbytes= read(fd,&D,sizeof(D))));
	if (sizeof(D) != nbytes) {
		fprintf(stderr,"read %d ",nbytes);
		perror("FIFO failed to block");
	}
#ifdef DEBUG
	f = (double)D.d;
	f = ((f) * NANOSECONDS_PER_TICK)/1000.0;
	n++;
	sum+=f;
	printf("Delay was %f microseconds, avg=%f, sec=%5d f=%2d, D={ %8d, %08x}\n",
		f,sum/(double)n, n/60, 1+(n%60), D.rtl_count, D.d);
#endif
	if(rtl_count && (rtl_count+1 != D.rtl_count))
		printf("Dropped %x tics at %x\n",
			D.rtl_count-(rtl_count-1), rtl_count);
	rtl_count = D.rtl_count;
//	*tics=rtl_count;
//	*delta_t=f;
//	return;
	return rtl_count;
}