#include <reg52.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define	RTX51_CLOCK	-15360	//for 18.432MHz crystal
#define Tasknum 4						//count tasks

sbit LED0 = P1^0;
sbit LED1 = P1^1;
sbit LED2 = P1^2;
sbit LED3 = P1^3;

//signed char os_wait(unsigned char Events, Timeout);

void Task0(void);
void Task1(void);
void Task2(void);
void Task3(void);

typedef union _ptrs
{
	struct
	{
		unsigned char lo,hi;
	}
	ptrs;
	unsigned int addr;
}
ptrs;

typedef struct
{
	ptrs ptr;
	unsigned int Task[Tasknum];					//Return Address
	unsigned char Timeout[Tasknum];			//Udalost ktora aktivuje task ...
	unsigned char Active_Task;					//Ktory task je aktivny???
}
Task_Vars;

Task_Vars Task;

//Environments variables start
float f;
unsigned char i,j,k;
//Environments variables end

void Kernel(void) interrupt 1 using 0
{
	EA=TR0=0;																						//Vypnem casovac T0 a globalne povolenie preruseni
	Task.ptr.addr=RTX51_CLOCK+(TH0*0x100+TL0)-84;				//Korekcia asi 84-cyklov x51 je od EA=0 az po EA=1, ale to treba upresnit ....
	TH0=Task.ptr.ptrs.lo;																//Aplikujem korekciu T0 v obratenom poradi
	TL0=Task.ptr.ptrs.hi;																//Aplikujem korekciu T0 v obratenom poradi
	Task.ptr.ptrs.hi=*(data char*)(SP-5);								//Ziskavam navratovu adresu prepinaneho tasku
	Task.ptr.ptrs.lo=*(data char*)(SP-4);								//Ziskavam navratovu adresu prepinaneho tasku
	Task.Task[Task.Active_Task++]=Task.ptr.addr;				//Navratovu adresu si ulozim do premennej
	if(Task.Active_Task>=Tasknum) Task.Active_Task=0;		//Neprekrocil som pocet spustenych taskov	
	//Task.Timeout[Task.Active_Task]--;
	Task.ptr.addr=Task.Task[Task.Active_Task];					//Adresu noveho tasku ulozim do zasobnika
	*(data char*)(SP-4)=Task.ptr.ptrs.lo;								//Prepinam sa na novy task v poradi ...
	*(data char*)(SP-5)=Task.ptr.ptrs.hi;								//Prepinam sa na novy task v poradi ...
	EA=TR0=1;																						//Zapnem casovac T0 a globalne povolenie preruseni
}

void Task0(void) using 1
{
	for(;;)
	{
		i++;
		LED0=~LED0;
		Task.Timeout[Task.Active_Task]=100;
	}
}

void Task1(void) using 1
{
	for(;;)
	{
		j++;
		LED1=~LED1;
	}
}

void Task2(void) using 1
{
	for(;;)
	{
		k++;
		LED2=~LED2;
	}
}

void Task3(void) using 2
{
	for(;;)
	{
		f+=0.001;
		LED3=~LED3;
	}
}

//void MyTask(void){}

void main(void)
{
	EA=1;
	ET0=1;
	TMOD|=0x01;
	PCON|=0x80;
	Task.ptr.addr=RTX51_CLOCK;
	TH0=Task.ptr.ptrs.lo;
	TL0=Task.ptr.ptrs.hi;
	//MyTask();
	//Task.Task[0]=(int)&MyTask;
	Task.Task[0]=(int)&Task0;
	Task.Task[1]=(int)&Task1;
	Task.Task[2]=(int)&Task2;
	Task.Task[3]=(int)&Task3;
	Task.Active_Task=0;
	TR0=1;
	Task0();
}
}