This example demonstrates the use of semaphores.
It implements a digital wrist clock in the way detailed in:
Bucker, La programmation cuncurrent, Press Polytechnique Romandes, Geneve.

To run the example type `make', 'make mknod', 'make insfifo',
`make insmod', and 'keybrd', then follow the menu.
Remember to kill the process 'screen' when you have finished yor test.


/* MODULE ClockChrono */

#define MODULE
#include <linux/module.h>
#include <linux/rt_sched.h>
#include <linux/rtf.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>

#include <CommandClock.h>
#include <CommandChrono.h>
#include <MenageHmsh.h>
#include <Display.h>
#include <Type.h>

#define Keyboard 0
#define Screen   1

void ClockChrono_Read(void)
{
	char ch;

	while(1) {
		rtf_get(Keyboard, &ch, 1);
		ch = toupper(ch);
		switch(ch) {
			case 'T': case 'R': case 'H': case 'M': case 'S':
				CommandClock_Put(ch);
				break;
			case 'C': case 'I': case 'F':
				CommandChrono_Put(ch);
			default:
				break;
		}
	}
}

void ClockChrono_Clock(void)
{
	const hundredthes = FALSE;
	MenageHmsh_tHour hour;
	MenageHmsh_tChain11 hourChain;
	char command;
	BOOLEAN display;

	MenageHmsh_Initialise(hour);
	MenageHmsh_Convert(hour, hundredthes, hourChain);
	Display_PutHour(hourChain);
	while(1) {
		CommandClock_Get(command);
		switch(command) {
			case 'R':
				rt_sleep(nano2counts(10000000LL));
				MenageHmsh_PlusOneUnit(&hour, display);
				break;
			case 'T': 
				ManageHmsh_InitialiseHundredthes(&hour);
				display = FALSE;
				break;
			case 'H': 
				MenageHmsh_AdvanceHours(&hour);
				display = TRUE;
				break;
			case 'M':
				MenageHmsh_AdvanceMinutes(&hour);
				display = TRUE;
				break;
			case 'S':
				MenageHmsh_AdvanceSeconds(&hour);
				display = TRUE;
			}
		if (display) {
			MenageHmsh_Convert(hour, hundredthes, hourChain);
			Display_PutHour(hourChain);
		}
	}
}

void ClockChrono_Chrono(void)
{
	MenageHmsh_tHour times;			
	MenageHmsh_tChain11 timesChain;
	BOOLEAN Intermediatetimes;
	MenageHmsh_tHour endIntermediateTimes;
	BOOLEAN display;
	BOOLEAN hundredthes;
	char command;

	command = 'R';
	while(1) {
		switch(command) {
			case 'R':
				MenageHmsh_Initialise(×);
				display = TRUE;
				hundredthes = FALSE;
				Intermediatetimes = FALSE;
				break;
			case 'C':
				rt_sleep(nano2counts(10000000LL));
				MenageHmsh_PlusOneUnit(×, display);
				if (Intermediatetimes) {
					Intermediatetimes = !MenageHmshEqual(
						times, endIntermadiateTimes);
					display = !Intermediatetimes;
					hundredthes = FALSE;
				}
				break;
			case 'I':
				Intermediatetimes = TRUE;
				endIntermadiateTimes = times;
				MenageHmsh_PlusNseconds(3, 
							&endIntermadiateTimes);
				display = TRUE;
				hundredthes = TRUE;
				break;
			case 'F':
				display = TRUE;
				hundredthes = TRUE;
		}
		if (display) {
			MenageHmsh_Convert(times, hundredthes, timesChain);
			Display_PutTimes(timesChain);
		}
		CommandChrono_Get(command);
	}
}

void ClockChrono_Write(void)
{
	int i;
	MenageHmsh_tChain11 chain;

	rtf_put(Screen, '\n', 1);
	while(1) {
		Display_Get(chain, receiver);
		rtf_put(Screen, '\n', 1);
		if (receiver == Display_destChrono) {
			rtf_put(Screen, '\n', 1);
		}
		for (i = 0; i < sizeof(chain); i++) {
			rtf_put(Screen, chain[i], 1);
		}
	}
}

RT_TASK read;
RT_TASK clock;
RT_TASK chrono;
RT_TASK write;

int init_module(void)
{
	rtf_create(Keyboard, 2000);
	rtf_create(Screen, 2000);
	rt_task_init(&read, ClockChrono_Read, 0, 2000, 0, 0);
	rt_task_init(&clock, ClockChrono_Clock, 0, 2000, 0, 0);
	rt_task_init(&chrono, ClockChrono_Chrono, 0, 2000, 0, 0);
	rt_task_init(&write, ClockChrono_Write, 0, 2000, 0, 0);
	rt_start_timer((int)nano2count(100000LL));
	return 0;
}

void cleanup_module(void)
{
	rt_stop_timer(();
	rtf_destroy(Keyboard);
	rtf_destroy(Screen);
	rt_task_delete(&read);
	rt_task_delete(&clock);
	rt_task_delete(&chrono);
	rt_task_delete(&write);
}


/* MODULE CommandClock */

#include <rt_sched.h>

enum (stopped, running) Clockstatus;
char buffer;
SEM notEmpty, notFull, mutex;

void CommandClock_Put(char command)
{
	rt_sem_wait(¬Full);
	rt_sem_wait(&mutex);
	if ((Clockstatus == running) == (command == 'T')) {
		buffer = command;
		rt_sem_signal(&mutex);
		rt_sem_signal(¬Empty);
	} else {
		rt_sem_signal(&mutex);
	}
}

void CommandClock_Get(char *command)
{
	switch (Clockstatus) {
		case stopped:
			rt_sem_wait(¬Empty);
			rt_sem_wait(&mutex);
			*command = buffer;
			if (*command == 'R') {
				Clockstatus = running;
			}
			rt_sem_signal(&mutex);
			rt_sem_signal(¬Empty);
			break;
		case running:
			rt_sem_wait(&mutex);
			*command = buffer;
			if (*command == 'T') {
				Clockstatus = stopped;
			}
			rt_sem_signal(&mutex);
			rt_sem_signal(¬Empty);
			break;
	}
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(¬Full, 1);
	rt_sem_init(&mutex, 1);
	Clockstatus = stopped;
	return 0
}

void cleanup_module(void)
{
}

/* MODULE CommandChrono */

#include <rt_sched.h>

const fiveSeconds = 5000000000LL;
enum (stoppedInitial, running, stoppedFinal) Chronostatus;
char buffer;
SEM notEmpty, notFull, mutex;

void CommandChrono_Put(char command)
{
	rt_sem_wait(¬Full);
	rt_sem_wait(&mutex);
	if ((Chronostatus == running) != (command == 'C')) {
		buffer = command;
		rt_sem_signal(&mutex);
		rt_sem_signal(¬Empty);
	} else {
		rt_sem_signal(&mutex);
	}
}

void CommandChrono_Get(char *command)
{
	switch (Chronostatus) {
		case stoppedInitial:
			rt_sem_wait(¬Empty);
			rt_sem_wait(&mutex);
			*command = buffer;
			Chronostatus = running;
			rt_sem_signal(&mutex);
			rt_sem_signal(¬Full);
			break;
		case running:
			rt_sem_wait(&mutex);
			if (rt_sem_wait_if(¬Full) > 0) {
				*command = 'C';
			} else {
				*command = buffer;
			}
			if (*command == 'F') {
				Chronostatus = stoppedFinal;
			}
			rt_sem_signal(&mutex);
			rt_sem_signal(¬Full);
			break;
		case stoppedFinal:
			rt_sem_wait_timed(¬Empty, nano2counts(fiveSeconds));
			rt_sem_wait(&mutex);
			*command = 'R';
			Chronostatus = stoppedInitial;
			rt_sem_signal(&mutex);
			break;
	}
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(¬Full, 1);
	rt_sem_init(&mutex, 1);
	Clockstatus = stoppedInitial;
	return 0;
}

void cleanup_module(void)
{
}

/* MODULE MenageHmsh */

#include <Type.h>

struct {int hours, minutes, secondes, hundredthes;} tHour;
char tChain11[11];
char digits[10] = {'0','1','2','3','4','5'.'6','7','8','9'};


void MenageHmsh_Initialise(tHour *h)
{
	h->hours = h->minutes = h->seconds = h->hundredthes = 0;
}

void MenageHmsh_Initialise_Hundredthes(tHour *h)
{
	h->hundredthes = 0;
}

BOOLEAN MenageHmsh_Equal(tHour h1, h2)
{
	return 	   (h1.hours == h2.hours)
		&& (h1.minutes == h2.minutes)
		&& (h1.seconds == h2.seconds)
		&& (h1.hundredthes == h2.hundredthes);
}

void MenageHmsh_AdvanceHours(tHour *h)
{
	h->hours = (h->hours + 1)%24;
}

void MenageHmsh_AdvanceMinutes(tHour *h)
{
	h->minutes = (h->minutes + 1)%60;
}

void MenageHmsh_AdvanceSeconds(tHour *h)
{
	h->seconds = (h->seconds + 1)%60;
}

void MenageHmsh_PlusOneSecond(tHour *h)
{
	MenageHmsh_AdvanceSeconds(h);
	if (h->seconds == 0) {
		MenageHmsh_AdvanceMinutes(h);
		if (h->minutes == 0) {
			MenageHmsh_AdvanceHours(h);
		}
	}
}

void MenageHmsh_PlusNSeconds(int n, tHour *h)
{
	int i;
	for (i = 1; i <= n; i++) {
		MenageHmsh_PlusOneSecond(h);
	}
}

void MenageHmsh_PlusOneUnit(tHour *h, BOOLEAN *reportSeconds)
{
	h->hundredthes = (h->hundredthes + 1)%100; 
	*reportSeconds = h->hundredthes == 0; 
	if (*reportSeconds) {
		MenageHmsh_PlusOneSecond(h);
	}
}

void MenageHmsh_Convert(tHour h, BOOLEAN hundredthes, tChaine11 chain)
{
	chain[0] = digits[h.hours/10];
	chain[1] = digits[h.hours%10];
	chain[2] = ':';
	chain[3] = digits[h.minutes/10];
	chain[4] = digits[h.minutes%10];
	chain[5] = ':';
	chain[6] = digits[h.seconds/10];
	chain[7] = digits[h.seconds%10];
	if (hundredthes) {
		chain[08] = '.';
		chain[09] = digits[h.hundredthes/10];
		chain[10] = digits[h.hundredthes%10];
	} else {
		chain[08] = chain[09] =	chain[10] = ' ';
	}
}

/* MODULE Display */

#include <rt_sched.h>
#include <MenageHmsh.h>

enum (empty, full) HourBufferstatus, TimesBufferstatus;
tChain11 hour;
tChain11 times;
SEM notEmpty, mutex;

void Display_PutHour(tChain11 chain)
{
	rt_sem_wait(&mutex);
	hour = chain;
	HourBufferstatus = full;
	rt_sem_signal(&mutex);
	rt_sem_signal(¬Empty);
}

void Display_PutTimes(tChain11 chain)
{
	rt_sem_wait(&mutex);
	times = chain;
	TimesBufferstatus = full;
	rt_sem_signal(&mutex);
	rt_sem_signal(¬Empty);
}

void Display_Get(tChain11 chain, tDest *receiver)
{
	rt_sem_wait(¬Empty);
	rt_sem_wait(&mutex);
	if (TimesBufferstatus == full) {
		receiver = destChrono; 
		chain = times;
		TimesBufferstatus = empty;
	} else {
		receiver = destClock; 
		chain = hours;
		HourBufferstatus = empty;
	}
	rt_sem_signal(&mutex);
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(&mutex, 1);
	TimesBufferstatus = empty;
	HourBufferstatus = empty;
	return 0;
}

void cleanup_module(void)
{
}

/* DEFINITION CommandClock */

extern void CommandClock_Put(char command);
extern void CommandClock_Get(char *command);

/* DEFINITION CommandChrono */

extern void CommandChrono_Put(char command);
extern void CommandChrono_Get(char *command);

/* DEFINITION MenageHmsh */

typedef char ch[11] tChain11;
typedef struct {int hours, minutes, seconds, hundredthes;} tHour;

extern void  MenageHmsh_Initialise(tHour *h);
extern void  MenageHmsh_InitialiseHundredthes(tHour *h);
extern void  MenageHmsh_AdvanceHours(tHour *h);
extern void  MenageHmsh_AdvanceMinutes(tHour *h);
extern void  MenageHmsh_AdvanceSeconds(tHour *h);
extern void  MenageHmsh_PlusNSeconds(int n, tHour *h);
extern void  MenageHmsh_PlusOneUnit(tHour *h, BOOLEAN *CarrySeconds);
extern void  MenageHmsh_Convert(tHour h, BOOLEAN *hundredthes, tChain11 chain);
extern BOOLEAN MenageHmsh_Equal(tHour h1, h2);

/* DEFINITION Display */

#include <MenageHmsh.h>

typedef enum (destClock, destChrono) tDest;

extern void Display_PutHour(tChain11 chain);
extern void Display_PutTimes(tChain11 chain);
extern void Display_Get(tChain11 *chain, tDest *receiver);

/* DEFINITION Type */

#define BOOLEAN int
#define TRUE 1
#define FALSE 0


/* KEYBOARD */

#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/rtf.h>
#include <asm/rt_time.h>
#include "control.h"

int main()
{
	int Keyboard, Screen;
	char ch;
	
	if ((Keyboard = open("/dev/rtf0", O_WRONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf0\n");
		exit(1);
	}

	if ((Screen = open("/dev/rtf1", O_RDONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf1\n");
		exit(1);
	}

	while((ch = getch()) != 'e') {
		write(Keyboard, &ch, 1);
	}

	while(1) {
		read(Screen, &ch, 1);
		printf("%c", ch);
	}
/* MODULE CLOCK */

#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <ctype.h>

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

#include "clock.h"

#define Keyboard 0
#define Screen   1

#define TICK_PERIOD     100000LL    /*  0.1 msec (  1  tick) */ 
#define POLLING_DELAY  1000000LL    /*    1 msec ( 10 ticks) */
#define ONE_UNIT      10000000LL    /*   10 msec (100 ticks) */
#define FIVE_SECONDS  5000000000LL

SEM sync;
SEM keybrd_sem;

BOOLEAN hide;
BOOLEAN pause;

RTIME OneUnit;

char read_keybrd(void)
{
	char char_command;

	rt_sem_wait(&keybrd_sem);
	rtf_get(Keyboard, &char_command, 1);
	return char_command;
}


int keybrd_handler(unsigned int fifo)
{
	rt_sem_signal(&keybrd_sem);
	return 0;
}


void ClockChrono_Read(int t)
{
	char ch;
	int run = 0;

	while(1) {
		ch = toupper(read_keybrd());
		switch(ch) {
			case 'T': case 'R': case 'H': case 'M': case 'S':
				CommandClock_Put(ch);
				break;
			case 'C': case 'I': case 'E':
				CommandChrono_Put(ch);
				break;
			case 'N':
				hide = ~hide;
				break;
			case 'P':
				pause = TRUE;
				rt_sleep(nano2count(FIVE_SECONDS));
				pause = FALSE;
				break;
			case 'K': case 'D':
				run |= ch;
				if (run == ('K' | 'D')) {
					rt_sem_signal(&sync);
					rt_sem_signal(&sync);
				}
				break;
		}
	}
}

void ClockChrono_Clock(int t)
{
	const hundredthes = FALSE;
	MenageHmsh_tHour hour;
	MenageHmsh_tChain11 hourChain;
	char command;
	BOOLEAN display;

	rt_sem_wait(&sync);
	MenageHmsh_Initialise(&hour);
/*
	MenageHmsh_Convert(hour, hundredthes, &hourChain);
	Display_PutHour(hourChain);
*/
	while(1) {
		CommandClock_Get(&command);
		switch(command) {
			case 'R':
				rt_sleep(OneUnit);
				MenageHmsh_PlusOneUnit(&hour, &display);
				break;
			case 'T': 
				MenageHmsh_InitialiseHundredthes(&hour);
				display = FALSE;
				break;
			case 'H': 
				MenageHmsh_AdvanceHours(&hour);
				display = TRUE;
				break;
			case 'M':
				MenageHmsh_AdvanceMinutes(&hour);
				display = TRUE;
				break;
			case 'S':
				MenageHmsh_AdvanceSeconds(&hour);
				display = TRUE;
			}
		if (display) {
			MenageHmsh_Convert(hour, hundredthes, &hourChain);
			Display_PutHour(hourChain);
		}
	}
}

void ClockChrono_Chrono(int t)
{
	MenageHmsh_tHour times;			
	MenageHmsh_tChain11 timesChain;
	BOOLEAN Intermediatetimes = FALSE;
	MenageHmsh_tHour endIntermediateTimes;
	BOOLEAN display;
	BOOLEAN hundredthes = FALSE;
	char command;

	rt_sem_wait(&sync);
	command = 'R';
	while(1) {
		switch(command) {
			case 'R':
				MenageHmsh_Initialise(×);
				display = TRUE;
				hundredthes = FALSE;
				Intermediatetimes = FALSE;
				break;
			case 'C':
				rt_sleep(OneUnit);
				MenageHmsh_PlusOneUnit(×, &display);
				if (Intermediatetimes) {
					Intermediatetimes = !MenageHmsh_Equal(
						times, endIntermediateTimes);
					display = !Intermediatetimes;
					hundredthes = FALSE;
				}
				break;
			case 'I':
				Intermediatetimes = TRUE;
				endIntermediateTimes = times;
				MenageHmsh_PlusNSeconds(3, 
							&endIntermediateTimes);
				display = TRUE;
				hundredthes = TRUE;
				break;
			case 'E':
				display = TRUE;
				hundredthes = TRUE;
		}
		if (display) {
			MenageHmsh_Convert(times, hundredthes, ×Chain);
			Display_PutTimes(timesChain);
		}
		CommandChrono_Get(&command);
	}
}

void ClockChrono_Write(int t)
{
	Display_tDest receiver;
	MenageHmsh_tChain11 chain;
	char buf[25] = "00:00:00   00:00:00:00";
	int i;

	while(1) {
		Display_Get(&chain, &receiver);

		if (receiver == destChrono) {
			for (i = 0; i < 11; i++) {
				buf[i+11] = chain.chain[i+1];
			}
		} else {
			for (i = 0; i < 8; i++) {
				buf[i] = chain.chain[i+1];
			}
		}
/*
		printk("\r%s  ",buf);
*/
			if (!hide && !pause) {
				rtf_put(Screen, chain.chain, 12);
			}
	}
}

RT_TASK read;
RT_TASK clock;
RT_TASK chrono;
RT_TASK write;

int init_module(void)
{
	hide = FALSE;
	pause = FALSE;
	OneUnit = nano2count(ONE_UNIT);
	rtf_create(Keyboard, 1000);
	rtf_create_handler(Keyboard, keybrd_handler);
	rtf_create(Screen, 1000);
	rt_sem_init(&sync, 0);
	rt_sem_init(&keybrd_sem, 0);
	rt_task_init(&read, ClockChrono_Read, 0, 2000, 0, 0, 0); 
	rt_task_init(&chrono, ClockChrono_Chrono, 0, 2000, 0, 0, 0);
	rt_task_init(&clock, ClockChrono_Clock, 0, 2000, 0, 0, 0);
	rt_task_init(&write, ClockChrono_Write, 0, 2000, 0, 0, 0);
	start_rt_timer((int)nano2count(TICK_PERIOD));
	rt_task_resume(&read);
	rt_task_resume(&chrono);
	rt_task_resume(&clock);
	rt_task_resume(&write);
	return 0;
}

void cleanup_module(void)
{
	stop_rt_timer();
	rtf_destroy(Keyboard);
	rtf_destroy(Screen);
	rt_task_delete(&read);
	rt_task_delete(&chrono);
	rt_task_delete(&clock);
	rt_task_delete(&write);
}
}
/* MODULE CMDCLK */

#define MODULE

#include <linux/module.h>

#include <rtl_sched.h>

static enum {stopped, running} Clockstatus;
static char buffer;
static SEM notEmpty, notFull;

void CommandClock_Put(char command)
{
	rt_sem_wait(¬Full);
	if ((Clockstatus == running) == (command == 'T')) {
		buffer = command;
		rt_sem_signal(¬Empty);
	} else {
		rt_sem_signal(¬Full);
	}
}

void CommandClock_Get(char *command)
{
	switch (Clockstatus) {
		case stopped:
			rt_sem_wait(¬Empty);
			*command = buffer;
			if (*command == 'R') {
				Clockstatus = running;
			}
			rt_sem_signal(¬Full);
			break;
		case running:
			if (rt_sem_wait_if(¬Empty) > 0) {
				*command = buffer;
				if (*command == 'T') {
					Clockstatus = stopped;
				}
				rt_sem_signal(¬Full);
			} else {
				*command = 'R';
			}
			break;
	}
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(¬Full, 1);
	Clockstatus = stopped;
	return 0;
}

void cleanup_module(void)
{
}
/* MODULE CHRONO */

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

#include <rtl_sched.h>

#include "clock.h"

#define FIVE_SECONDS 5000000000LL

static RTIME fiveSeconds;
static enum {stoppedInitial, running, stoppedFinal} Chronostatus;
static char buffer;
static SEM notEmpty, notFull;
static BOOLEAN buffered;

void CommandChrono_Put(char command)
{
	rt_sem_wait(¬Full);
	if ((Chronostatus == running) != (command == 'C')) {
		buffer = command;
		rt_sem_signal(¬Empty);
	} else {
		rt_sem_signal(¬Full);
	}
}

void CommandChrono_Get(char *command)
{
	switch (Chronostatus) {
		case stoppedInitial:
			if (buffered) { 
				buffered = FALSE;
			} else {
				rt_sem_wait(¬Empty);
			}
			*command  = buffer;
			Chronostatus = running;
			rt_sem_signal(¬Full);
			break;
		case running:
			if (rt_sem_wait_if(¬Empty) > 0) {
				*command = buffer;
	 			if (*command == 'E') {
					Chronostatus = stoppedFinal;
				}
				rt_sem_signal(¬Full);
			} else {
				*command = 'C';
			}
			break;
		case stoppedFinal:
			if (rt_sem_wait_timed(¬Empty, fiveSeconds) >= 0) {
				buffered = TRUE;
			}
			*command = 'R';
			Chronostatus = stoppedInitial;
			break;
	}
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(¬Full, 1);
	Chronostatus = stoppedInitial;
	buffered = FALSE;
	fiveSeconds = nano2count(FIVE_SECONDS);
	return 0;
}

void cleanup_module(void)
{
}
/* MODULE CHRONO */

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

#include <rtl_sched.h>

#include "clock.h"

#define FIVE_SECONDS 5000000000LL

static RTIME fiveSeconds;
static enum {stoppedInitial, running, stoppedFinal} Chronostatus;
static char buffer;
static SEM notEmpty, notFull;
static BOOLEAN buffered;

void CommandChrono_Put(char command)
{
	rt_sem_wait(¬Full);
	if ((Chronostatus == running) != (command == 'C')) {
		buffer = command;
		rt_sem_signal(¬Empty);
	} else {
		rt_sem_signal(¬Full);
	}
}

void CommandChrono_Get(char *command)
{
	switch (Chronostatus) {
		case stoppedInitial:
			if (buffered) { 
				buffered = FALSE;
			} else {
				rt_sem_wait(¬Empty);
			}
			*command  = buffer;
			Chronostatus = running;
			rt_sem_signal(¬Full);
			break;
		case running:
			if (rt_sem_wait_if(¬Empty) > 0) {
				*command = buffer;
	 			if (*command == 'E') {
					Chronostatus = stoppedFinal;
				}
				rt_sem_signal(¬Full);
			} else {
				*command = 'C';
			}
			break;
		case stoppedFinal:
			if (rt_sem_wait_timed(¬Empty, fiveSeconds) >= 0) {
				buffered = TRUE;
			}
			*command = 'R';
			Chronostatus = stoppedInitial;
			break;
	}
}

int init_module(void)
{
	rt_sem_init(¬Empty, 0);
	rt_sem_init(¬Full, 1);
	Chronostatus = stoppedInitial;
	buffered = FALSE;
	fiveSeconds = nano2count(FIVE_SECONDS);
	return 0;
}

void cleanup_module(void)
{
}
/* MODULE DISPCLK */

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

#include <rtl_sched.h>

#include "clock.h"

#define ONE_SHOT

static char digits[10] = {'0','1','2','3','4','5','6','7','8','9'};

void MenageHmsh_Initialise(MenageHmsh_tHour *h)
{
	h->hours = h->minutes = h->seconds = h->hundredthes = 0;
}

void MenageHmsh_InitialiseHundredthes(MenageHmsh_tHour *h)
{
	h->hundredthes = 0;
}

BOOLEAN MenageHmsh_Equal(MenageHmsh_tHour h1, MenageHmsh_tHour h2)
{
	return 	   (h1.hours == h2.hours)
		&& (h1.minutes == h2.minutes)
		&& (h1.seconds == h2.seconds)
		&& (h1.hundredthes == h2.hundredthes);
}

void MenageHmsh_AdvanceHours(MenageHmsh_tHour *h)
{
	h->hours = (h->hours + 1)%24;
}

void MenageHmsh_AdvanceMinutes(MenageHmsh_tHour *h)
{
	h->minutes = (h->minutes + 1)%60;
}

void MenageHmsh_AdvanceSeconds(MenageHmsh_tHour *h)
{
	h->seconds = (h->seconds + 1)%60;
}

void MenageHmsh_PlusOneSecond(MenageHmsh_tHour *h)
{
	MenageHmsh_AdvanceSeconds(h);
	if (h->seconds == 0) {
		MenageHmsh_AdvanceMinutes(h);
		if (h->minutes == 0) {
			MenageHmsh_AdvanceHours(h);
		}
	}
}

void MenageHmsh_PlusNSeconds(int n, MenageHmsh_tHour *h)
{
	int i;
	for (i = 1; i <= n; i++) {
		MenageHmsh_PlusOneSecond(h);
	}
}

void MenageHmsh_PlusOneUnit(MenageHmsh_tHour *h, BOOLEAN *reportSeconds)
{
	h->hundredthes = (h->hundredthes + 1)%100; 
	*reportSeconds = h->hundredthes == 0; 
	if (*reportSeconds) {
		MenageHmsh_PlusOneSecond(h);
	}
}

void MenageHmsh_Convert(MenageHmsh_tHour h, BOOLEAN hundredthes, MenageHmsh_tChain11 *chain)
{
	chain->chain[1] = digits[h.hours/10];
	chain->chain[2] = digits[h.hours%10];
	chain->chain[3] = ':';
	chain->chain[4] = digits[h.minutes/10];
	chain->chain[5] = digits[h.minutes%10];
	chain->chain[6] = ':';
	chain->chain[7] = digits[h.seconds/10];
	chain->chain[8] = digits[h.seconds%10];
	if (hundredthes) {
		chain->chain[9] = '.';
		chain->chain[10] = digits[h.hundredthes/10];
		chain->chain[11] = digits[h.hundredthes%10];
	} else {
		chain->chain[9] = chain->chain[10] = chain->chain[11] = ' ';
	}
}

enum {empty, full} HourBufferstatus, TimesBufferstatus;
MenageHmsh_tChain11 hour;
MenageHmsh_tChain11 times;
SEM notEmpty, mutex;

void Display_PutHour(MenageHmsh_tChain11 chain)
{
	rt_sem_wait(&mutex);
	hour = chain;
	hour.chain[0] = 'h';
	if (HourBufferstatus == empty) {
		HourBufferstatus = full;
		rt_sem_signal(¬Empty);
	}
	rt_sem_signal(&mutex);
}

void Display_PutTimes(MenageHmsh_tChain11 chain)
{
	rt_sem_wait(&mutex);
	times = chain;
	times.chain[0] = 't';
	if (TimesBufferstatus == empty) {
		TimesBufferstatus = full;
		rt_sem_signal(¬Empty);
	}
	rt_sem_signal(&mutex);
}

void Display_Get(MenageHmsh_tChain11 *chain, Display_tDest *receiver)
{
	rt_sem_wait(¬Empty);
	rt_sem_wait(&mutex);
	if (TimesBufferstatus == full) {
		*receiver = destChrono; 
		*chain = times;
		TimesBufferstatus = empty;
	} else if (HourBufferstatus == full) {
		*receiver = destClock; 
		*chain = hour;
		HourBufferstatus = empty;
	}
	rt_sem_signal(&mutex);
}

int init_module(void)
{
#ifdef ONE_SHOT
	rt_set_oneshot_mode();
#endif
	rt_sem_init(¬Empty, 0);
	rt_sem_init(&mutex, 1);
	TimesBufferstatus = empty;
	HourBufferstatus = empty;
	return 0;
}

void cleanup_module(void)
{
}
/* KEYBOARD */

#include <stdio.h>
#include <errno.h>
#include <termio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
//#include <tcl.h>
#include <unistd.h>
#include <curses.h>
#include <sys/ioctl.h>

#include <rtl_fifo.h>
#include <asm/rt_time.h>

static void menu(void)
{
	printf("___________________________________________________\n");
	printf("|                CLOCK COMMANDS                   |\n");
	printf("|t-stop clock, r-run, h-hour, m-minutes, s-seconds|\n");
	printf("|              CHRONOMETER COMMANDS               |\n");
	printf("|    c-run, i-display intermediate time, e-stop   |\n");
	printf("|               CONTROL COMMANDS                  |\n");
	printf("| n-show/hide display, p-display menu f-end this  |\n");
	printf("---------------------------------------------------\n");
	printf("\n");
}

void main()
{
	int Keyboard, pid;
	char ch;
	char k = 'k';
	struct termio my_kb, orig_kb;

	pid = fork();
	if (!pid) {
		execlp("screen", "screen");
	}
	usleep(10000);
	
	if ((Keyboard = open("/dev/rtf0", O_WRONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf0\n");
		exit(1);
	}

	if (write(Keyboard, &k, 1) < 0 ) {
		fprintf(stderr, "Can't send initial command to RT-task\n");
		exit(1);
	}

	ioctl(0, TCGETA, &orig_kb);
	my_kb = orig_kb;
	my_kb.c_lflag &= ~ECHO;
	menu();
	do {
		ioctl(0, TCSETAF, &my_kb);
	        ch = getchar();
		ioctl(0, TCSETAF, &orig_kb);
	        if (ch == 'p' || ch == 'P') {
			menu();
		}
		if (write(Keyboard, &ch, 1) < 0 ) {
			fprintf(stderr, "Can't send command to RT-task\n");
			exit(1);
		}
	} while(ch != 'f');
	kill(pid, SIGKILL);
	exit(0);
}
/* SCREEN */

#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm/rt_time.h>

#include <rtl_fifo.h>

int main()
{
	unsigned int Keyboard, Screen, i;
	char d = 'd';
	char chain[12];
	char displine[40] = "CLOCK-> 00:00:00  CHRONO-> 00:00:00";
	
	if ((Keyboard = open("/dev/rtf0", O_WRONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf0\n");
		exit(1);
	}

	if (write(Keyboard, &d, 1) < 0 ) {
		fprintf(stderr, "Can't send initial command to RT-task\n");
		exit(1);
	}

        close(Keyboard);

	if ((Screen = open("/dev/rtf1", O_RDONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf1\n");
		exit(1);
	}

	while(1) {
		read(Screen, chain, 12);
		if (chain[0] == 't') {
			for (i = 0; i < 11; i++) {
				displine[i+27] = chain[i+1];
			}
		} else if (chain[0] == 'h') {
			for (i = 0; i < 8; i++) {
				displine[i+8] = chain[i+1];
			}
		}
		printf("%s\n", displine);
	}
}