#include <stdio.h>
#include "softED2.h"
#include "I2C.h"
#include "89C51RD2.h"



/*I/O promenne */
sbit rele_1=P2^5;
sbit rele_2=P2^6;

sbit nap_bat=P0^0;		//napeti baterie	
sbit nabij_bat=P2^7;	//nabijeni baterie

sbit err=P2^0;			//ledka err
sbit ok=P2^1;			//ledka ok
sbit piezo=P2^2;

sbit muxA=P3^5;			
sbit muxB=P3^6;

sbit SCL=P1^0;	//hodiny I2C
sbit SDA=P1^1;	//data I2C

bit send;
bit validData;
bit validIDN;

/*makra*/

#define clk 0	 //frekvence I2C
#define wait 500	//cekani I2C 5 ms

#define rtc 0xA0	//adresa rtc
#define mem 0xA2	//adresa pameti

#define length 33		//pocet bytu v pam na jednoho uzivatele
#define mem_end 0x7FFF	//posledni pozice v pameti
#define mem_stck 64		//deleni pameti
#define point 0xFF30	//priznak nastaveni casu

/* globalni promenne */
 unsigned char inUARTbuffer[64];
 unsigned char outUARTbuffer[64];
 char pocet_in;
 char pocet_out;
 static char pocet_mist=0;
 char error;
static unsigned char IDN[6];
static unsigned int cekani=0;
static int hystereze=0;


/******-----hlavni program-----******/
int main(void)
{


TMOD=0x01;	// Inicializace casovace
initUART();	//inicializace seriove linky

ES = 1;		// povoleni preruseni od seriove linky
EA = 1; 	// povoleni vzniku preruseni
EX0 = 1;	//povoleni preruseni od INT0


muxB=0;		//nastaveni muxu; 0-ctecka, 1-komunikacni rozhrani
beep(10);	//pisknuti po zapnuti
err=1;		//zhasnuti cervene LED
ok=0;		//rozsviceni zelene LED


  while(1)
	{
	
	cekani++;

	if(muxB && validData)
	  {
	  PCconnect();
	  cekani=0;
	  }
	if(cekani>30000)
	  {
	    cekani=0;
	  	nabijeni();
		validTime();
	  }  
	  
	if(validIDN)
	  findUser();

	if(error==1)
	  {
	  error=0;
	  sendError(0xE8);
	  
	  }
	

	
	}

}


/****funkce****/
/*----inicializace seriove linky----*/
void initUART(void)
{

SCON = 0x50;	// UART PRI 8 BITECH, NEBOLI MOD 1

// Inicializace casovace

/*	//timer1
PCON=0x00; 		//SMOD1= 1; 1/32, pri nule 1/64
TMOD = TMOD | 0X20; // NASTAVI CITAC 1 DO MODU 2. 
TH1 = 0XF3;		// 4800 Bds PRI 12 MHz -max rychlost!!
TR1 = 1;		// PUSTI CHOD 1.cas
*/
	//timer2
TCLK=1;		//zdroj hodin UARTu T2
RCLK=1;		//zdroj hodin UARTu T2
RCAP2H=0xFF;//rychlost 9600 Bds pri 12 MHz
RCAP2L=0xD9;
TR2 = 1;	// pusti chod 2.casovace

//ES = 1;		// povoleni preruseni od seriove linky	

validData=0;	//pro prijata data z PC, 1- platna
pocet_in=0;
pocet_out=0;

}
/*----pausa5us----*/
void pause(unsigned int doba)
{
TH0 = 0xFE;	//prednastaveni citace 0
TL0 = 0x42;	//prednastaveni citace 0
TR0=1; 		//spusteni citace 0

	while(doba>=1)
	{
		if(TF0==1)
		{
			doba--;		
			TH0=0xFE;	//prednastaveni citace 0
			TL0=0x42;
			TF0=0;		//opetovne spusteni citace 0
		}
	}
}
/*----pausa10ms----*/
void pause10(unsigned int doba)
{

TH0 = 0xD8;	//prednastaveni citace
TL0 = 0xEF;
TR0=1; 		//spusteni citace

	while(doba>=1)
	{
		if(TF0==1)
		{
			doba--;		
			TH0=0xD8;//prednastaveni citace 0
			TL0=0xEF;//prednastaveni citace 0
			TF0=0;	//opetovne spusteni citace 0
		}
	}
}

/*----pisknuti----*/
void beep(unsigned int doba)
{
	while(doba>=1)
	{
		doba--;
		piezo=~piezo;
		pause(1);
		piezo=~piezo;
		pause(1);
	}
}

/*----nabijeni baterie pokud je vybita----*/
void nabijeni()
{
	if(nap_bat)	//1-nabito
	{
	hystereze++;
		if(hystereze==20)//zavedeni hystereze pro ukonceni nabijeni
		{
			hystereze=0;
			nabij_bat=0;	//vypnuti dobijeni
//			err=1;			//kontolni ledka
		}
	}
	else
	{
		nabij_bat=1;	//zapnuti nabijeni
//		err=0;
	}

}
/*----overeni nastaveni casu ----*/
void validTime(void)
{
  char pom[1];
  readI2C(&pom,rtc,point,1);
    if(pom[0] == 0)
	  {
	  err=0;
	  pause10(20);
      err=1;
      }
}

/*----preruseni od seriove linky----*/
void seriovaLinka(void) interrupt 4
{
int i;

	if(RI == 1)	//pro prijem
	{

		inUARTbuffer[pocet_in]= SBUF;
		pocet_in++;
	

			if((muxB==0)&&(pocet_in==16))	//pro prijem retezce z RFID ctecky
				verifyString();

			if(muxB==1)		//komunikace pres rozhrani
			{
			 
						if (inUARTbuffer[0] == 0xAA)   //pokud je na prvni pozici uvodni byte
						  {
						   
							if (pocet_in == inUARTbuffer[1])  // a jsou prijata vsechna data paketu
							  {  
								if (verifyCheck() == 1)	//kontrola a dekodovani paketu
								  { 
									pocet_in=pocet_in-4;	//orezani kontrolnich bytu prenosu
										for(i=0;i<(pocet_in);i++)
											inUARTbuffer[i]=inUARTbuffer[i+2];
									validData=1;
									//PCconnect();
								   }   
								          
							  }		  
				
						  }
						else
						  {
						   pocet_in=0;
						   //sendError(1);  //pokud neni na 1.bajt 0xAA - nahlas chybu prenosu
						  }
			}
			
	RI = 0;

	}
	else	//pro vysilani 
	{
		TI = 0; 
		send = 0;
		
	
	}
}
/*----odeslani bytu----*/
void sendByte(char byte)
{
send = 1;
SBUF=byte;
	while (send==1);   // cekani az se vysle byte po UARTu      
       	
} 
/*----odeslani OutBufferu----*/
void sendOutBuffer(unsigned char *buffer,unsigned char pocet)
{
int i;
int check;

//muxB=1;		//prepnuti muxu	!!!! osetrit !!!!	
sendByte (170);              // synch. byte  
check=170;
sendByte(pocet+4);                // pocet bytu v paketu        
check=check ^ (pocet+4);
	for(i=0;i<pocet;i++)
	{
		sendByte(buffer[i]);                // odeslani dat       
		check=check ^ buffer[i];
	}

sendByte(check);	//kontrolni soucet              
sendByte(0xF0);		//ukonc. byte

}
/*----overeni kontrolniho souctu paketu----*/
char verifyCheck(void)
{  
  char i,check;

  check=0;		
  for (i=0;i<(inUARTbuffer[1]-1);i++)	//vypocet xoru vsech dat
       check=check ^ inUARTbuffer[i];
      
  if (check == 0) {// pokud vypocteny check xor check v in_bufferu=0 - data jsou v poradku
      if (inUARTbuffer[inUARTbuffer[1]-1] == 0xF0)   // kontrola jestli je na konci paketu ukoncovaci byte
         return 1;
      else
         return 0; 
      }
  else
      return 0;        
}
/*----odeslani chyboveho hlaseni----*/
void sendError(char typ)
{     
 int check;
  
 sendByte (170);              // sync. byte  
 check=170;
 sendByte(4);                // pocet bytu v paketu        
 check=check ^ 4;
 sendByte(typ);                // id erroru        
 check=check ^ typ;
 sendByte(check);              
 sendByte(0xF0);
} 



/*@@@@@@@@@@@@@@@ ctecka@@@@@@@@@@@@@@@@@@*/
/*----overeni kontrolniho soucu retezce cipu----*/
void verifyString(void)
{
int i;
char bufferAscii[16];
char check;

	if((inUARTbuffer[0]==0x02)&&(inUARTbuffer[15]==0x03))//pokud je start a stop znak
	{
		for(i=0;i<16;i++)	//prevedeni do ascii znaku
		{
			bufferAscii[i] = (inUARTbuffer[i]-0x30);
			if(bufferAscii[i]>15)
				bufferAscii[i] = (bufferAscii[i]-7);
		}

		for(i=0;i<6;i++)	//slouceni do bytu
			IDN[i]=(bufferAscii[i*2+1]<<4)|(bufferAscii[i*2+2]&0x0F);

		check=IDN[0];	//vytvoreni souctu
		for(i=1;i<5;i++)
			check=check^IDN[i];
			
			if(check == IDN[5])
			{
				beep(30);
				validIDN = 1;
				pocet_in = 0;
				//findUser();
			}
			else
			{
				beep(30);		//ton erroru
				pause10(20);
				beep(30);
				pause10(20);
				beep(30);

			}
	}
}
/*----vyhledani uzivatele v pameti----*/
void findUser(void)
{
  int i=0;
  unsigned char den;
  unsigned char pomcas[10];
  unsigned char pomprava[10];
  unsigned char poc_usr;
  bit prava=0;
  bit pass=0;

//  ES = 0;	//zakazani preruseni od seriove linky
  err=0;
  readI2C(&pomcas,mem,mem_end,1);		//cteni poctu uzivatelu v pameti
  poc_usr=pomcas[0];
    while(pass==0)
	  {
	    //pause(wait);
	    readI2C(&pomcas,mem,(i * mem_stck),5);	//cteni dat uzivatele z pam - pouze IDN
		  if(IDN[0] == pomcas[0])				//porovnani IDN
		    {
			if(IDN[1] == pomcas[1])
			  {
			  if(IDN[2] == pomcas[2])
			    {
				if(IDN[3] == pomcas[3])
				  {
				  if(IDN[4] == pomcas[4])
				    {
					  pass=1;
					  //beep(30);
					  i--;
					}
				  }
				}
			  }
			}
		i++;
		if(i>=poc_usr)
		  {
		  	  beep(200);		//ton erroru
			  pause10(30);
			  beep(200);
			  pause10(30);
			  beep(200);
			  break;
		  }	
	  }
  if(pass)
  {
  
  readI2C(&pomcas,rtc,0xFF03,4);		//cteni casu z rtc
  den=(pomcas[3]>>5)&0x07;				//vypocet dne v tydnu
  pomprava[5]=den;
  readI2C(&pomprava,mem,((i*mem_stck)+5+(4*den)),4);	//cteni prav v tento den  
  
//  cas = 60*pomcas[1]+pomcas[0];	// akt. cas v minutach
//  prichod = 60*pomprava[0]+pomprava[1];	//prichod v minutach
//  odchod = 60*pomprava[2]+pomprava[3];	//odchod v minutach
    if((pomprava[0]<pomcas[1]))//&&(pomprava[2]>pomcas[1]))	//overeni casu prichodu
	  prava=1;
	else  
	  if((pomcas[1]==pomprava[0]))  
	    if(pomprava[1]<=pomcas[0])
  	      prava=1;
		else
		  prava=0;
	  else
		prava=0;
	if(pomprava[2]>pomcas[1])
	  prava=1;
	else  
	  if((pomcas[1]==pomprava[2]))  
	     if(pomprava[3]>=pomcas[0]) 
		   prava=1;
		 else
		   prava=0;
	  else
	    prava=0; 
//	else
//	  if((pomcas[1]-pomprava[0])>=0)
	  
	  
//  	if(pomcas[0]<=pomprava[3])//(pomcas[1]<=pomprava[2])&&(pomcas[0]<=pomprava[3]))	//overeni casu odchodu
// pause(wait);
// writeI2C(&pomprava,mem,64,10);	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  if(prava)		//pokud ma uzivatel povolen pristup
    {
        rele_2 = 0;		//sepnuti kontaktu rele
		beep(400);
		pause10(200);
		rele_2 = 1;
	 
	}
  else
    {
	  beep(200);		//ton erroru
	  pause10(30);
	  beep(200);
	  pause10(30);
	  beep(200);	
	}
  }
  pocet_in=0;
  validIDN=0;
//  ES = 1;	//povoleni preruseni od seriove linky
  err=1;
}


/*****I2C*****/
/*----odeslani bytu po I2C sbernici----*/
char writeByteI2C(char byte)
{
  int i;

    for(i=7;i>=0;i--)
    {	
      SCL = 0;
      SDA = (byte>>(i)) & 0x01;
      pause(clk);
	  SCL = 1;
      pause(clk);
    }

  SCL=0;
  SDA=1;  // prepnuti I/O pinu na vstup
  SCL=1;
  pause(clk);
    if(SDA==0)	//cteni ACK
      return 1;
    else
      return 0;

}
/*----prijeti bytu po I2C sbernici----*/
char readByteI2C(void)
{
  int i;
  char byte = 0;

  SCL=0;
  SDA=1;

    for(i=0;i<8;i++)
    {	
      pause(clk);
	  SCL = 1;
	  pause(clk);
      byte |= SDA;
	  SCL = 0;
	    if(i!=7)
          byte=(byte<<1);  
    }

return byte;
}

/*----odeslani dat po I2C sbernici----*/
void writeI2C(unsigned char *byte,unsigned char dev_adr,short int mem_adr,int N)
{
  int i;

  SDA=1;	//init
  SCL=1;

  SDA = 0;	//start
  pause(clk);
  
  if(!(writeByteI2C(dev_adr)))	//dev.adress
  	error=1;

  if((0xFF00 & mem_adr)!=0xFF00)	//pro pripad pameti adresovane pouze spodnim bytem, horni je FF
	{	
	  if(!(writeByteI2C(0x00FF & (mem_adr>>8))))		//mem.adress horni byte
		error=1;
	}
  if(!(writeByteI2C(0x00FF & mem_adr)))					//mem.adress dolni byte
	error=1;

	for(i=0;i<N;i++)
	{
  		if(!(writeByteI2C(byte[i])))//(*((&byte)+i))))
  	    	error=1;
	}


  SCL=0;	//stop		
  SDA=0;
  pause(clk);		
  SCL=1;
  pause(clk);
  SDA=1;
}
/*----prijeti dat po I2C sbernici----*/
char readI2C(unsigned char *byte,char dev_adr,short int mem_adr,int N)
{
  int i=0;

  SDA=1;	//init
  SCL=1;

  SDA = 0;	//start
  pause(clk);
  
  if(!(writeByteI2C(dev_adr)))	//dev.adress
	error=1;

  if((0xFF00 & mem_adr)!=0xFF00)	//pro pripad pameti adresovane pouze spodnim bytem, horni je FF
	{
	  if(!(writeByteI2C(0x00FF & (mem_adr>>8))))		//mem.adress 1.
		error=1;
	}
  if(!(writeByteI2C((0x00FF) & mem_adr)))				//mem.adress 2.
	error=1;

  SCL=0;
  pause(clk);
  SCL=1;
  pause(clk);
  SDA = 0;	//repeat start
  pause(clk);

  if(!(writeByteI2C(dev_adr|0x01)))		//dev.adress
	error=1;

  if(N > 1)
  	{
		for(i=0;i<(N-1);i++)	//N-1 protoze posledni byte ctu vzdy 
		  {
	  		byte[i]=readByteI2C();
			
			SDA=0;		//ACK
			SCL=1;			
			pause(clk);				
		  
		  }
	
	}	
  
  byte[i]=readByteI2C();	 //noACK, ctu jeden, nebo posledni byte

  SCL=0;	//stop		
  SDA=0;
  pause(clk);		
  SCL=1;
  pause(clk);
  SDA=1;

  return byte;
}


/*################## funkce prog ######################*/
/*----externi preruseni INT0----*/
void EXinterupt(void) interrupt 0
{
  muxB=1;
  err=0;
  pause10(10);
  err=1;
  EX0 = 0;	//zakazani preruseni od INT0
}
/*----vyber cinnosti s prijatymi daty----*/
void PCconnect(void)
{
  if(inUARTbuffer[pocet_in-1] == 0x10)
	PCsendIDN();
  if(inUARTbuffer[pocet_in-1] == 0x20)
	PCaddUsrMem();
  if(inUARTbuffer[pocet_in-1] == 0x30)
	PCreadMem();
  if(inUARTbuffer[pocet_in-1] == 0x40)
	PCchangeCountMem();
  if(inUARTbuffer[pocet_in-1] == 0x50)
	PCeraseMem();
  if(inUARTbuffer[pocet_in-1] == 0x60)
	PCsetDate();
  if(inUARTbuffer[pocet_in-1] == 0xA0)
	PCendConnect();

}
/*----cteni a odeslani IDN----*/
void PCsendIDN(void)
{
  muxB=0;			//prepnu na ctecku
  pocet_in=0;
  validData=0;
  validIDN=0;
  while(validIDN==0); //cekani az se precte IDN
  validIDN=0;
  
  muxB=1;	//prepnu na kom rozhrani
  sendOutBuffer(&IDN,5);
  pocet_in=0;
  validData=0;

}
/*----pridani uzivatele do pameti----*/
void PCaddUsrMem(void)	//prvni uzivatel ulozen na nulte pozici	
{
  unsigned char pom[2];
  unsigned char poc_usr;
err=0;  
  readI2C(&pom,mem,mem_end,1);		//cteni poctu uzivatelu v pameti
  poc_usr=pom[0];
  
  pause(wait);
  writeI2C(&inUARTbuffer,mem,(poc_usr * mem_stck),length);	//(poc_usr * mem_stck)ulozeni dat uzivatele z PC do pam
  poc_usr++;
  pom[0]=poc_usr;
  
  pause(wait);
  writeI2C(&pom,mem,mem_end,1);		//ulozeni poctu uzivatelu
err=1;
  sendByte(0xCC);				//odeslani kontrolniho bytu-ulozeno v pam
  pocet_in=0;
  validData=0;
}
/*----cteni dat uzivatelu z pameti----*/
void PCreadMem(void)
{
  int i;
  unsigned char pom[2];
  unsigned char poc_usr;
 
  readI2C(&pom,mem,mem_end,1);		//cteni poctu uzivatelu v pameti
  poc_usr = pom[0];
 
  	for(i=0;i<poc_usr;i++)	// 
	  {
		err=0;
	  	readI2C(&outUARTbuffer,mem,(i * mem_stck),length);	//cteni dat uzivatele z pam
		sendOutBuffer(&outUARTbuffer,length);
		pocet_in=0;
		validData=0;
		while(validData==0);	//cekani na odpoved prenosu
		err=1;  
	  }

  outUARTbuffer[0]=0xFA;			//odeslani priznaku precteni cele pameti
  sendOutBuffer(&outUARTbuffer,1);  
	  
  pocet_in=0;
  validData=0;	  
	  
}
/*----zmena poctu uzivatelu v pameti----*/
void PCchangeCountMem(void)
{
  writeI2C(&inUARTbuffer,mem,mem_end,1);	//ulozeni poctu uzivatelu z PC do pam  
  sendByte(0xCC);				//odeslani kontrolniho bytu-ulozeno v pam
  pocet_in=0;
  validData=0;
  
}
/*----mazani pameti----*/
void PCeraseMem(void)
{
  int i;
  unsigned char zero_pole[length];
err=0;
  for(i=0;i<length;i++)	//vytvoreni nuloveho pole
    zero_pole[i]=0;
  for(i=0;i<128;i++)
    {
      writeI2C(&zero_pole,mem,i*mem_stck,length);	//zapsani nuloveho pole do pameti
      pause(wait);
	}
  sendByte(0xCC);				//odeslani kontrolniho bytu-ulozeno v pam
  pocet_in=0;
  validData=0;
err=1;
}
/*----nastaveni casu a data----*/
void PCsetDate(void)
{
  unsigned char pom[5];
err=0;
  pom[0] = 0x80;					//zastaveni citani 
  writeI2C(&pom,rtc,0xFF00,1);
  pause(wait);
  writeI2C(&inUARTbuffer,rtc,0xFF02,5);	//nastaveni casu
  pause(wait);
  pom[0] = 0x00;					//spusteni citani 
  writeI2C(&pom,rtc,0xFF00,1);
err=1;
  sendByte(0xCC);				//odeslani kontrolniho bytu-ulozeno v pam
  pocet_in=0;
  validData=0;
  pom[0] = 0xFF; 
  writeI2C(&pom,rtc,point,1);

}
/*----ukonceni komunikace----*/
void PCendConnect(void)
{
err=0;
  muxB=0;		//prepnuti na ctecku
  pocet_in=0;
  validData=0;
  cekani=200;	//doba hlavni smycky
  EX0 = 1;	//povoleni preruseni od INT0
err=1;
}
