This example demonstrates the support of floating point operations in
real-time tasks by calculating a sine, that can be seen wave squared on a scope
connected to the parallel port. Since it interrupts a front linux process
(check) that is carrying out a floating point summation it is
possible to verify the appropriate working of fpu save/restores.
Be carefull about the macro TICK_PERIOD its value is now set for a 200Mhz
PPro, which can be too much for a less powerfull machine.

To run this example you must first compile and boot the RT-kernel,
then install the rt-scheduler module of this variant.

To run the example type `make', 'make mknod', 'make insfifo',
`insmod rt_process' and 'check'.
By toggling the 'f' key you will put the floating point support on and off
and verify that the calculations carried out in 'check' are accordingly right
or wrong.

/* Produce a rectangular wave on output 0 of a parallel port */


#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <asm/io.h>

#include <rtl_fifo.h>
#include <rtl_sched.h>
#include <math.h>



/* the address of the parallel port -- you probably should change this */

#define ONE_SHOT

#define LPT 0x378

#define TICK_PERIOD 20000

#define STACK_SIZE 2000

#define LOOPS 1000000000

#define PERIOD .00005

#define RTF 0

#define CMD 1

RT_TASK mytask;

void fun(int t) {
	int flag;
	double sine[2] = {1., 2.,};
	unsigned int loops = LOOPS;

	while (loops--) {
		sine[0] = (6.28/PERIOD)*((double)rt_get_time()/1193810.);
		sine[1] = sin(sine[0]);
		t = sine[1] > 0. ? 1 : 0;
		outb(t, LPT);
		rtf_put(RTF, sine, sizeof(sine));
		if (rtf_get(CMD, &flag, sizeof(flag)) == sizeof(flag)) {
			rt_task_use_fpu(rt_whoami(), flag);
		}
		rt_task_wait_period();
	}
}


int init_module(void)
{
	RTIME now, tick_period;

#ifdef ONE_SHOT
	rt_set_oneshot_mode();
#endif
	rtf_create(RTF, 4000);
	rtf_create(CMD, 100);
	rt_task_init(&mytask, fun, 0, STACK_SIZE, 0, 1, 0);
	tick_period = start_rt_timer((int)nano2count(TICK_PERIOD));
	rt_linux_use_fpu(1);
	now = rt_get_time();
	rt_task_make_periodic(&mytask, now + tick_period, tick_period);
	return 0;
}


void cleanup_module(void)
{
	stop_rt_timer();
	rtf_destroy(RTF);
	rtf_destroy(CMD);
	rt_task_delete(&mytask);
}