This example features some NTASKS real-time tasks running periodically.
On each period a server task is messaged to set/reset a bit on the parallel 
port. By choosing an appropriate timing one can produce a rectangular wave
which can be watched on an oscilloscope plugged into it.
Be carefull about the macro TICK_PERIOD its value is now set for a 200Mhz
PPro, which can be to much for a less powerfull machine.

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

To run the example type `make' and `insmod rt_process'.


/* 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_sched.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 20000

#define END 0xFFFF

#define NTASKS 21

RT_TASK task[NTASKS];


void driver(int t)
{
	RT_TASK *task[NTASKS];
	int i, l;
	unsigned int msg;
	RTIME tick_period;
	RTIME now;

	for (i = 1; i < NTASKS; i++) {
		task[i] = rt_receive(0, &msg);
	}
	for (i = 1; i < NTASKS; i++) {
		rt_return(task[i], i);
	}
#ifdef ONE_SHOT
	rt_set_oneshot_mode();
#endif
	tick_period = start_rt_timer(nano2count(TICK_PERIOD));
	now = rt_get_time();
	rt_task_make_periodic(rt_whoami(), now + 5, tick_period);

	msg = 0;
	l = LOOPS;
	while(l--) {
		for (i = 1; i < NTASKS; i++) {
			if (i%2) {
				rt_rpc(task[i], msg, &msg);
			} else {
				rt_send(task[i], msg);
				msg = 1 - msg;
			}
			rt_task_wait_period();
		}
	}
	for (i = 1; i < NTASKS; i++) {
		rt_send(task[i], END);
	}
	rt_task_delete(rt_whoami());
}


void fun(int t)
{
	unsigned int msg;
	rt_rpc(&task[0], t, &msg);
	while(msg != END) {
		rt_receive(&task[0], &msg);
		outb((msg & 1), LPT);
		if (rt_isrpc(&task[0])) {
			rt_return(&task[0], 1 - msg);
		}
	}
	outb(0, LPT);
	rt_task_delete(rt_whoami());
}


int init_module(void)
{
	int i;

	rt_task_init(&task[0], driver, 0, STACK_SIZE, 0, 0, 0);
	for (i = 1; i < NTASKS; i++) {
		rt_task_init(&task[i], fun, i, STACK_SIZE, 0, 0, 0);
	}
	for (i = 0; i < NTASKS; i++) {
		rt_task_resume(&task[i]);
	}
	return 0;
}


void cleanup_module(void)
{
	int i;

	stop_rt_timer();
	for (i = 0; i < NTASKS; i++) {
		rt_task_delete(&task[i]);
	}
}